Книга: Practical Common Lisp
Value Accumulation
Value Accumulation
The value accumulation clauses are perhaps the most powerful part of LOOP
. While the iteration control clauses provide a concise syntax for expressing the basic mechanics of looping, they aren't dramatically different from the equivalent mechanisms provided by DO
, DOLIST
, and DOTIMES
.
The value accumulation clauses, on the other hand, provide a concise notation for a handful of common loop idioms having to do with accumulating values while looping. Each accumulation clause starts with a verb and follows this pattern:
verb form [ into var ]
Each time through the loop, an accumulation clause evaluates form and saves the value in a manner determined by the verb. With an into
subclause, the value is saved into the variable named by var. The variable is local to the loop, as if it'd been declared in a with
clause. With no into
subclause, the accumulation clause instead accumulates a default value for the whole loop expression.
The possible verbs are collect
, append
, nconc
, count
, sum
, maximize
, and minimize
. Also available as synonyms are the present participle forms: collecting
, appending
, nconcing
, counting
, summing
, maximizing
, and minimizing
.
A collect
clause builds up a list containing all the values of form in the order they're seen. This is a particularly useful construct because the code you'd have to write to collect a list in order as efficiently as LOOP
does is more painful than you'd normally write by hand.[238] Related to collect
are the verbs append
and nconc
. These verbs also accumulate values into a list, but they join the values, which must be lists, into a single list as if by the functions APPEND
or NCONC
.[239]
The remaining accumulation clauses are used to accumulate numeric values. The verb count
counts the number of times form is true, sum
collects a running total of the values of form, maximize
collects the largest value seen for form, and minimize
collects the smallest. For instance, suppose you define a variable *random*
that contains a list of random numbers.
(defparameter *random* (loop repeat 100 collect (random 10000)))
Then the following loop will return a list containing various summary information about the numbers:
(loop for i in *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))