Do Forms
do ((var [start [step]])*) (stop result*) form* ⇒ result*
Iterate over a group of statements while a test condition holds. Variables are bound within the iteration and stepped in parallel.
Using do* causes the variable bindings and steppings to be performed sequentially rather than in parallel.
(do ((i 0 (1+ i))) ;init to 0, step 1
((>= i 4) (print 'done)) ;end test, result-form
(print i)) ;⇒ NIL [prints 0..3, done]
(do ((n 0 (1+ n)) ;init to 0, step 1
(current 0 next) ;init to 0, read old value of next
(next 1 (+ current next))) ;init to 1, reads old values
((= 10 n) current)) ;⇒ 55 end test and result-form
(do ()
((> (get-universal-time) *some-future-date*))
(print "waiting...")
(sleep 60))
dotimes (var i [result]) form* ⇒ result*
Iterate over a series of integers. Terminate loop immediately with return.
(dotimes (i 10)
(print i))
(dotimes (i 10 (print 'done))
(print i))
Map/Reduce/Filter
dolist (var list [result]) form* ⇒ result*
Iterate over the elements of a list. Terminate loop immediately with return.
(dolist (x '(1 2 3 4))
(print x))
(dolist (x '(1 2 3 4) (print 'done))
(print x))
mapcar
Iterates over successive list elements and returns the accumlated results. mapc is similar except the results are not accumulated and the first list is returned.
(mapcar #'+ '(1 2) '(3 4)) ;⇒ (4 6)
(mapcar (alexandria:compose #'print #'1+) '(1 2 3)) ;⇒ (2 3 4) [prints 2,3,4]
maplist
mapcan
mapcon
mapc
mapl
alexandria:mappend fn &rest lists… ⇒ list
Zips up list components and returns a flattened list. fn must return a list.
(mappend #'list '(1 3) '(2 4)) ;⇒ ((1 2) (3 4)) ⇒ (1 2 3 4)
(flet ((zipper (x y) (list (+ x y))))
(mappend #'zipper '(1 3) '(2 4))) ;⇒ ((+ 1 2) (+ 3 4)) ⇒ (3 7)
alexandria:map-product fn list &rest lists… ⇒ list
Results of calling fn
with one argument per list for every combination.
(map-product #'list '(1 2) '(3 4) '(5 6))
;⇒ ((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
map result-type fn &rest seqs* ⇒ result
Applies the function to elements of each sequence in turn. The result sequence is as long as the shortest of the sequences.
(map 'list #'cons '(a b) '(c d)) ;⇒ ((A . C) (B . D))
(map 'vector #'(lambda (x) (* 2 x)) '(1 2 3)) ;⇒ #(2 4 6)
map-into result-seq fn &rest seqs* ⇒ result-seq
Destructively modifies result-seq to contain the results of applying the function to each element in the argument seqs in turn.
(map-into '(a b c) #'oddp '(1 2 3 4 5 6)) ;⇒ (T NIL T)
remove-if-not fn seq &key from-end start end count key ⇒ seq
Filter
(remove-if-not #'oddp '(0 1 2 3 4)) ;⇒ (1 3)
(remove-if-not (alexandria:disjoin #'zerop #'oddp) '(0 1 2 3 4)) ;⇒ (0 1 3)
remove-if fn seq &key from-end start end count key ⇒ seq
(remove-if #'oddp '(0 1 2 3 4)) ;⇒ (0 2 4)
(remove-if (alexandria:disjoin #'zerop #'oddp) '(0 1 2 3 4)) ;⇒ (2 4)
reduce fn seq &key key from-end start end initial-value ⇒ result
(reduce #'* '(1 2 3 4 5)) ;⇒ 120
alexandria:map-combinations fn seq &key start end length copy
alexandria:map-derangements fn seq &key start end copy
alexandria:map-permutations fn seq &key start end length copy
alexandria:doplist (key val plist &optional values) forms*
Hash-Tables
maphash function hash-table ⇒ nil
Iterate over hash-table entries, calling function with two arguments, the key and value of that entry.
(setf ht (alexandria:plist-hash-table '(:x 10 :y 20))
buf (list))
(maphash #'(lambda (key val)
(push (list key val) buf)) ht) ;⇒ NIL
buf ;⇒ ((:Y 20) (:X 10))
alexandria:maphash-keys function hash-table ⇒ nil
Like maphash, but calls function with each key in the hash-table.
(setf buf (list))
(alexandria:maphash-keys #'(lambda (key)
(push key buf)) ht) ;⇒ NIL
buf ;⇒ (:Y :X)
alexandria:maphash-values function hash-table ⇒ nil
Like maphash, but calls function with each value in the hash-table.
(setf buf (list))
(alexandria:maphash-values #'(lambda (val)
(push val buf)) ht) ;⇒ NIL
buf ;⇒ (20 10)
loop for [key|value] being the [hash-keys|hash-values] in hash-table
Using the extended form of loop, iterate over hash-table entries binding to key and value.
(loop
for key being the hash-keys in ht
for val being the hash-values in ht
collect (list key val)) ;⇒ ((:X 10) (:Y 20))
iterate for (key value) in-hashtable hash-table
Using the iterate package, iterate over hash-table entries binding to key and value.
(iter (for (key val) in-hashtable ht)
(collect (list key val))) ;⇒ ((:X 10) (:Y 20))
Recursion
Tesing if a list contains an element using tail-recursion:
(defun our-member (obj lst)
(if (null lst) ;finished if empty list, return nil
nil
(if (eql (car lst) obj) ;if obj is first list element, return list
lst
(our-member obj (cdr lst))))) ;else, test against rest of list
Using an accumulator:
(defun fac (x)
(labels ((fac2 (x acc) ;function takes current step and accumulated results
(if (= x 0)
acc ;if done, return accumulated results list
(fac2 (- x 1) (* acc x))))) ;else, call again with stepped down arg and accumulation
(fac2 x 1))) ;initial call to start