LISP: Removing elements from list already existing in another

729 views Asked by At

Can anybody explain to me why this:

(remove-if #'(lambda (var) (member var (list "x"))) (list "x" "y" "z"))

returns this:

("x" "y" "z")

but this:

(remove-if #'(lambda (var) (member var (list 1))) (list 1 2 4))

returns this:

(2 4)

?

1

There are 1 answers

2
sds On

The Answer

Pass :test #'equal to member:

(remove-if #'(lambda (var) (member var (list "x") :test #'equal)) (list "x" "y" "z"))
==> ("y" "z")

Note that

(eql "x" "x")
==> NIL
(equal "x" "x")
==> T
(eql 1 1)
==> T

The Reason

The default One-Argument Test in Common Lisp is eql.

It is the most reasonable choice between the 4(!) general purpose comparison functions provided for by the ANSI CL standard:

  • eq is too implementation-dependent and does not work as one probably wants on numbers and characters
  • equal and equalp traverse objects and thus take a long time for huge ones and may never terminate for circular ones.

See also the difference between eq, eql, equal, and equalp in Common Lisp.

The Right Way

Use set-difference instead of remove-if + member.