Four other handy functions are EVERY
, SOME
, NOTANY
, and NOTEVERY
, which iterate over sequences testing a boolean predicate. The first argument to all these functions is the predicate, and the remaining arguments are sequences. The predicate should take as many arguments as the number of sequences passed. The elements of the sequences are passed to the predicate—one element from each sequence—until one of the sequences runs out of elements or the overall termination test is met: EVERY
terminates, returning false, as soon as the predicate fails. If the predicate is always satisfied, it returns true. SOME
returns the first non-NIL
value returned by the predicate or returns false if the predicate is never satisfied. NOTANY
returns false as soon as the predicate is satisfied or true if it never is. And NOTEVERY
returns true as soon as the predicate fails or false if the predicate is always satisfied. Here are some examples of testing just one sequence:
(every #'evenp #(1 2 3 4 5)) ==> NIL
(some #'evenp #(1 2 3 4 5)) ==> T
(notany #'evenp #(1 2 3 4 5)) ==> NIL
(notevery #'evenp #(1 2 3 4 5)) ==> T
These calls compare elements of two sequences pairwise:
(every #'> #(1 2 3 4) #(5 4 3 2)) ==> NIL
(some #'> #(1 2 3 4) #(5 4 3 2)) ==> T
(notany #'> #(1 2 3 4) #(5 4 3 2)) ==> NIL
(notevery #'> #(1 2 3 4) #(5 4 3 2)) ==> T
Finally, the last of the sequence functions are the generic mapping functions. MAP
, like the sequence predicate functions, takes a MAP
returns a new sequence containing the result of applying the function to subsequent elements of the sequences. Like CONCATENATE
and MERGE
, MAP
needs to be told what kind of sequence to create.
(map 'vector #'* #(1 2 3 4 5) #(10 9 8 7 6)) ==> #(10 18 24 28 30)
MAP-INTO
is like MAP
except instead of producing a new sequence of a given type, it places the results into a sequence passed as the first argument. This sequence can be the same as one of the sequences providing values for the function. For instance, to sum several vectors—a
, b
, and c
—into one, you could write this:
(map-into a #'+ a b c)
If the sequences are different lengths, MAP-INTO
affects only as many elements as are present in the shortest sequence, including the sequence being mapped into. However, if the sequence being mapped into is a vector with a fill pointer, the number of elements affected isn't limited by the fill pointer but rather by the actual size of the vector. After a call to MAP-INTO
, the fill pointer will be set to the number of elements mapped. MAP-INTO
won't, however, extend an adjustable vector.
The last sequence function is REDUCE
, which does another kind of mapping: it maps over a single sequence, applying a two-argument function first to the first two elements of the sequence and then to the value returned by the function and subsequent elements of the sequence. Thus, the following expression sums the numbers from one to ten:
(reduce #'+ #(1 2 3 4 5 6 7 8 9 10)) ==> 55
REDUCE
is a surprisingly useful function—whenever you need to distill a sequence down to a single value, chances are you can write it with REDUCE
, and it will often be quite a concise way to express what you want. For instance, to find the maximum value in a sequence of numbers, you can write (reduce #'max numbers)
. REDUCE
also takes a full complement of keyword arguments (:key
, :from-end
, :start
, and :end
) and one unique to REDUCE
(:initial-value
). The latter specifies a value that's logically placed before the first element of the sequence (or after the last if you also specify a true :from-end
argument).
The other general-purpose collection provided by Common Lisp is the hash table. Where vectors provide an integer-indexed data structure, hash tables allow you to use arbitrary objects as the indexes, or keys. When you add a value to a hash table, you store it under a particular key. Later you can use the same key to retrieve the value. Or you can associate a new value with the same key—each key maps to a single value.
With no arguments MAKE-HASH-TABLE
makes a hash table that considers two keys equivalent if they're the same object according to EQL
. This is a good default unless you want to use strings as keys, since two strings with the same contents aren't necessarily EQL
. In that case you'll want a so-called EQUAL
hash table, which you can get by passing the symbol EQUAL
as the :test
keyword argument to MAKE-HASH-TABLE
. Two other possible values for the :test
argument are the symbols EQ
and EQUALP
. These are, of course, the names of the standard object comparison functions, which I discussed in Chapter 4. However, unlike the :test
argument passed to sequence functions, MAKE-HASH-TABLE
's :test
can't be used to specify an arbitrary function—only the values EQ
, EQL
, EQUAL
, and EQUALP
. This is because hash tables actually need two functions, an equivalence function and a
The GETHASH
function provides access to the elements of a hash table. It takes two arguments—a key and the hash table—and returns the value, if any, stored in the hash table under that key or NIL
.[129] For example:
(defparameter *h* (make-hash-table))
(gethash 'foo *h*) ==> NIL
(setf (gethash 'foo *h*) 'quux)
(gethash 'foo *h*) ==> QUUX
Since GETHASH
returns NIL
if the key isn't present in the table, there's no way to tell from the return value the difference between a key not being in a