PontiusPeladele
PontiusPeladele

Reputation: 3

LISP - Write the function (REMOVE EL), that removes given atom or list from another list on all levels of the list

I have the following task:

To build the function (REMOVE EL), that removes given atom or list from another list, and this should apply on each level of the list

Example :

L=(A B A (B A C X ) X B)
(REMOVE A L ) -> (B (B C X) X B)

I wrote the following code :

(defun removeel(el tree)
  (mapcan (lambda(subtree)
            (cond ((null subtree) (list nil))
                  ((consp subtree) (list (removeel el subtree)))
                  ((eql subtree el) nil)
                  (t (list subtree))))
          tree))

The problem is that when I remove atom, it works excellent

(removeel 'B' (A B A (B A C X ) X B))
 (A A (A C X) X) 

But it doesn't work If I want to remove a list

(removeel '(B A C X) ' (A B A (B A C X ) X B))
  (A B A (B A C X) X B)

What should be done to make it to remove lists too ?

Upvotes: 0

Views: 206

Answers (1)

leetwinski
leetwinski

Reputation: 17849

the simplest way would be to introduce optional equality test function, as in remove standard procedure.

it could look this way:

(defun rem-rec (item data &key (test #'eql))
  (mapcar (lambda (x) (if (listp x)
                          (rem-rec item x :test test)
                          x))
      (remove item data :test test)))

CL-USER> (rem-rec 1 `(1 2 (3 4 (1 2 3)) (1 (1 2 3) 3 4)))
;;=> (2 (3 4 (2 3)) ((2 3) 3 4))

for lists equality you can use equal (or equalp or anything more specific)

CL-USER> (rem-rec '(1 2 3) '(1 2 (3 4 (1 2 3)) (1 (1 2 3) 3 4)) :test #'equal)
;;=> (1 2 (3 4) (1 3 4))

Upvotes: 1

Related Questions