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