Chapter 14
Sequences

 14.1 Simple Sequence Functions
 14.2 Concatenating, Mapping, and Reducing Sequences
 14.3 Modifying Sequences
 14.4 Searching Sequences for Items
 14.5 Sorting and Merging

The type sequence encompasses both lists and vectors (one-dimensional arrays). While these are different data structures with different structural properties leading to different algorithmic uses, they do have a common property: each contains an ordered set of elements. Note that nil is considered to be a sequence of length zero.

Some operations are useful on both lists and arrays because they deal with ordered sets of elements. One may ask the number of elements, reverse the ordering, extract a subsequence, and so on. For such purposes Common Lisp provides a set of generic functions on sequences.

Note that this remark, predating the design of the Common Lisp Object System, uses the term “generic” in a generic sense, and not necessarily in the technical sense used by CLOS (see chapter 2).

elt  reverse map remove
length  nreverse some remove-duplicates
subseq  concatenateevery delete
copy-seq position notany delete-duplicates
fill  find noteverysubstitute
replace  sort reduce nsubstitute
count  merge search mismatch

Some of these operations come in more than one version. Such versions are indicated by adding a suffix (or occasionally a prefix) to the basic name of the operation. In addition, many operations accept one or more optional keyword arguments that can modify the operation in various ways.

If the operation requires testing sequence elements according to some criterion, then the criterion may be specified in one of two ways. The basic operation accepts an item, and elements are tested for being eql to that item. (A test other than eql can be specified by the :test or :test-not keyword. It is an error to use both of these keywords in the same call.) The variants formed by adding -if and -if-not to the basic operation name do not take an item, but instead a one-argument predicate, and elements are tested for satisfying or not satisfying the predicate. As an example,

(remove item sequence)

returns a copy of sequence from which all elements eql to item have been removed;

(remove item sequence :test #’equal)

returns a copy of sequence from which all elements equal to item have been removed;

(remove-if #’numberp sequence)

returns a copy of sequence from which all numbers have been removed.

If an operation tests elements of a sequence in any manner, the keyword argument :key, if not nil, should be a function of one argument that will extract from an element the part to be tested in place of the whole element. For example, the effect of the MacLisp expression (assq item seq) could be obtained by

(find item sequence :test #’eq :key #’car)

This searches for the first element of sequence whose car is eq to item.

X3J13 voted in June 1988 to allow the :key function to be only of type symbol or function; a lambda-expression is no longer acceptable as a functional argument. One must use the function special operator or the abbreviation #’ before a lambda-expression that appears as an explicit argument form.

For some operations it can be useful to specify the direction in which the sequence is conceptually processed. In this case the basic operation normally processes the sequence in the forward direction, and processing in the reverse direction is indicated by a non-nil value for the keyword argument :from-end. (The processing order specified by the :from-end is purely conceptual. Depending on the object to be processed and on the implementation, the actual processing order may be different. For this reason a user-supplied test function should be free of side effects.)

Many operations allow the specification of a subsequence to be operated upon. Such operations have keyword arguments called :start and :end. These arguments should be integer indices into the sequence, with startend (it is an error if start > end). They indicate the subsequence starting with and including element start and up to but excluding element end. The length of the subsequence is therefore endstart. If start is omitted, it defaults to zero; and if end is omitted or nil, it defaults to the length of the sequence. Therefore if both start and end are omitted, the entire sequence is processed by default. For the most part, subsequence specification is permitted purely for the sake of efficiency; one could simply call subseq instead to extract the subsequence before operating on it. Note, however, that operations that calculate indices return indices into the original sequence, not into the subsequence:

(position #\b "foobar" :start 2 :end 5)  3
(position #\b (subseq "foobar" 2 5))  1

If two sequences are involved, then the keyword arguments :start1, :end1, :start2, and :end2 are used to specify separate subsequences for each sequence.

X3J13 voted in June 1988 (and further clarification was voted in January 1989 ) to specify that these rules apply not only to all built-in functions that have keyword parameters named :start, :start1, :start2, :end, :end1, or :end2 but also to functions such as subseq that take required or optional parameters that are documented as being named start or end.

This may be summarized as follows. Let x be the sequence within which indices are to be considered. Let s be the “start” argument for that sequence of any standard function, whether explicitly specified or defaulted, through omission, to zero. Let e be the “end” argument for that sequence of any standard function, whether explicitly specified or defaulted, through omission or an explicitly passed nil value, to the active length of x, as returned by length. Then it is an error if the test (<= 0 s e (length x)) is not true.

For some functions, notably remove and delete, the keyword argument :count is used to specify how many occurrences of the item should be affected. If this is nil or is not supplied, all matching items are affected.

In the following function descriptions, an element x of a sequence “satisfies the test” if any of the following holds:

In each case keyfn is the value of the :key keyword argument (the default being the identity function). See, for example, remove.

In the following function descriptions, two elements x and y taken from sequences “match” if either of the following holds:

See, for example, search.

X3J13 voted in June 1988 to allow the testfn or predicate to be only of type symbol or function; a lambda-expression is no longer acceptable as a functional argument. One must use the function special operator or the abbreviation #’ before a lambda-expression that appears as an explicit argument form.

You may depend on the order in which arguments are given to testfn; this permits the use of non-commutative test functions in a predictable manner. The order of the arguments to testfn corresponds to the order in which those arguments (or the sequences containing those arguments) were given to the sequence function in question. If a sequence function gives two elements from the same sequence argument to testfn, they are given in the same order in which they appear in the sequence.

Whenever a sequence function must construct and return a new vector, it always returns a simple vector (see section 2.5). Similarly, any strings constructed will be simple strings.

[Function] complement fn

Returns a function whose value is the same as that of not applied to the result of applying the function fn to the same arguments. One could define complement as follows:

(defun complement (fn)
  #’(lambda (&rest arguments)
      (not (apply fn arguments))))

One intended use of complement is to supplant the use of :test-not arguments and -if-not functions.

(remove-if-not #’virtuous senators)
   (remove-if (complement #’virtuous) senators)

(remove-duplicates telephone-book
                   :test-not #’mismatch)
   (remove-duplicates telephone-book
                      :test (complement #’mismatch))