Higher-Order Function Variants
For each of the functions just discussed, Common Lisp provides two higher-order function variants that, in the place of the item argument, take a function to be called on each element of the sequence. One set of variants are named the same as the basic function with an -IF
appended. These functions count, find, remove, and substitute elements of the sequence for which the function argument returns true. The other set of variants are named with an -IF-NOT
suffix and count, find, remove, and substitute elements for which the function argument does not return true.
(count-if #'evenp #(1 2 3 4 5)) ==> 2
(count-if-not #'evenp #(1 2 3 4 5)) ==> 3
(position-if #'digit-char-p "abcd0001") ==> 4
(remove-if-not #'(lambda (x) (char= (elt x 0) #\f))
#("foo" "bar" "baz" "foom")) ==> #("foo" "foom")
According to the language standard, the **-IF-NOT**
variants are deprecated. However, that deprecation is generally considered to have itself been ill-advised. If the standard is ever revised, it’s more likely the deprecation will be removed than the **-IF-NOT**
functions. For one thing, the **REMOVE-IF-NOT**
variant is probably used more often than **REMOVE-IF**
. Despite its negative-sounding name, **REMOVE-IF-NOT**
is actually the positive variant—it returns the elements that do satisfy the predicate. 7
The -IF
and -IF-NOT
variants accept all the same keyword arguments as their vanilla counterparts except for :test
, which isn’t needed since the main argument is already a function.8 With a :key
argument, the value extracted by the :key
function is passed to the function instead of the actual element.
(count-if #'evenp #((1 a) (2 b) (3 c) (4 d) (5 e)) :key #'first) ==> 2
(count-if-not #'evenp #((1 a) (2 b) (3 c) (4 d) (5 e)) :key #'first) ==> 3
(remove-if-not #'alpha-char-p
#("foo" "bar" "1baz") :key #'(lambda (x) (elt x 0))) ==> #("foo" "bar")
The **REMOVE**
family of functions also support a fourth variant, **REMOVE-DUPLICATES**
, that has only one required argument, a sequence, from which it removes all but one instance of each duplicated element. It takes the same keyword arguments as **REMOVE**
, except for :count
, since it always removes all duplicates.
(remove-duplicates #(1 2 1 2 3 1 2 3 4)) ==> #(1 2 3 4)