I would not write this function, becuase, as Rainer Joswig says, the standard already provides SET-DIFFERENCE
. Nonetheless, if I had to provide an implementation of the function, this is the one I would use:
(defun filter (a b)
(let ((table (make-hash-table)))
(map 'nil (lambda (e) (setf (gethash e table) t)) a)
(remove-if (lambda (e) (gethash e table)) b)))
Doing it this way provides a couple of advantages, the most important one being that it only traverses b
once; using a hash table to keep track of what elements are in a
is likely to perform much better if a
is long.
Also, using the generic sequence functions like MAP
and REMOVE-IF
mean that this function can be used with strings and vectors as well as lists, which is an advantage even over the standard SET-DIFFERENCE
function. The main downside of this approach is if you want extend the function with a :TEST
argument that allows the user to provide an equality predicate other than the default EQL
, since CL hash-tables only work with a small number of pre-defined equality predicates (EQ
, EQL
, EQUAL
and EQUALP
to be precise).