Looping Over Collections and Packages
The for
clauses for iterating over lists are much simpler than the arithmetic clauses. They support only two prepositional phrases, in
and on
.
A phrase of this form:
for var in list-form
steps var over all the elements of the list produced by evaluating list-form.
(loop for i in (list 10 20 30 40) collect i) ==> (10 20 30 40)
Occasionally this clause is supplemented with a by
phrase, which specifies a function to use to move down the list. The default is **CDR**
but can be any function that takes a list and returns a sublist. For instance, you could collect every other element of a list with a loop like this:
(loop for i in (list 10 20 30 40) by #'cddr collect i) ==> (10 30)
An on
prepositional phrase is used to step var over the cons cells that make up a list.
(loop for x on (list 10 20 30) collect x) ==> ((10 20 30) (20 30) (30))
This phrase too can take a by
preposition:
(loop for x on (list 10 20 30 40) by #'cddr collect x) ==> ((10 20 30 40) (30 40))
Looping over the elements of a vector (which includes strings and bit vectors) is similar to looping over the elements of a list except the preposition across
is used instead of in
.3 For instance:
(loop for x across "abcd" collect x) ==> (#\a #\b #\c #\d)
Iterating over a hash table or package is slightly more complicated because hash tables and packages have different sets of values you might want to iterate over—the keys or values in a hash table and the different kinds of symbols in a package. Both kinds of iteration follow the same pattern. The basic pattern looks like this:
(loop for var being the things in hash-or-package ...)
For hash tables, the possible values for things are hash-keys
and hash-values
, which cause var
to be bound to successive values of either the keys or the values of the hash table. The hash-or-package form is evaluated once to produce a value, which must be a hash table.
To iterate over a package, things can be symbols
, present-symbols
, and external-symbols
, which cause var to be bound to each of the symbols accessible in a package, each of the symbols present in a package (in other words, interned or imported into that package), or each of the symbols that have been exported from the package. The hash-or-package form is evaluated to produce the name of a package, which is looked up as if by **FIND-PACKAGE**
or a package object. Synonyms are also available for parts of the for
clause. In place of the
, you can use each
; you can use of
instead of in
; and you can write the things in the singular (for example, hash-key
or symbol
).
Finally, since you’ll often want both the keys and the values when iterating over a hash table, the hash table clauses support a using
subclause at the end of the hash table clause.
(loop for k being the hash-keys in h using (hash-value v) ...)
(loop for v being the hash-values in h using (hash-key k) ...)
Both of these loops will bind k
to each key in the hash table and v
to the corresponding value. Note that the first element of the using
subclause must be in the singular form.4