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:

  1. for var in list-form

steps var over all the elements of the list produced by evaluating list-form.

  1. (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:

  1. (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.

  1. (loop for x on (list 10 20 30) collect x) ==> ((10 20 30) (20 30) (30))

This phrase too can take a by preposition:

  1. (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:

  1. (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:

  1. (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.

  1. (loop for k being the hash-keys in h using (hash-value v) ...)
  2. (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