e20
e20

Reputation: 53

LISP - removing an element from a list with nested lists

I need to remove an element from a list which contain inner lists inside. The predefined element should be removed from every inner list too.

I have started working with the following code:

(SETQ L2 '(a b ( a 2 b) c 1 2 (D b (a s 4 2) c 1 2 a) a )) ; defined my list 

; Created a function for element removing
(defun elimina (x l &optional l0)
(cond (( null l)(reverse l0))
((eq x (car l))(elimina x (cdr l) l0))
(T (elimina x (cdr l) (cons (car l) l0))))
)

(ELIMINA 'a L2) 

But unfortunately it removes only elements outside the nested lists.

I have tried to create an additional function which will remove the element from the inner lists.

(defun elimina-all (x l)
(cond ((LISTP (CAR L))(reverse l)(elimina x (car l)))
(T (elimina-all  x (CDR L)))
)
)

but still unsuccessfully.

Can you please help me to work it out?

Thank you in advance.

Upvotes: 0

Views: 4905

Answers (3)

Will Soares
Will Soares

Reputation: 31

I was looking for the same answer as you and, unfortunately, I couldn't completely understand the answers above so I just worked on it and finally I got a really simple function in Lisp that does exactly what you want.

(defun remove (a l)
(cond
    ((null l) ())
        ((listp (car l))(cons (remove a (car l))(remove a (cdr l))))
        ((eq (car l) a) (remove a (cdr l)))
        (t (cons (car l) (remove a (cdr l))))
        )
    )

The function begins with two simple cases, which are: 'list is null' and 'first element is a list'. Following this you will "magically" get the car of the list and the cdr of the list without the given element. To fixed that up to be the answer for the whole list you just have to put them together using cons.

Upvotes: 0

user797257
user797257

Reputation:

First of all, I'd suggest you read this book, at least, this page, it explains (and also gives very good examples!) of how to traverse a tree, but most importantly, of how to combine functions to leverage more complex tasks from more simple tasks.

;; Note that this function is very similar to the built-in
;; `remove-if' function. Normally, you won't write this yourself
(defun remove-if-tree (tree predicate)
  (cond
    ((null tree) nil)
    ((funcall predicate (car tree))
     (remove-if-tree (cdr tree) predicate))
    ((listp (car tree))
     (cons (remove-if-tree (car tree) predicate)
           (remove-if-tree (cdr tree) predicate)))
    (t (cons (car tree)
             (remove-if-tree (cdr tree) predicate)))))

;; Note that the case of the symbol names doesn't matter
;; with the default settings of the reader table. I.e. `D' and `d'
;; are the same symbol, both uppercase.
;; Either use \ (backslash) or || (pipes
;; around the symbol name to preserve the case. Eg. \d is the
;; lowercase `d'. Similarly, |d| is a lowercase `d'.
(format t "result: ~s~&"
        (remove-if-tree
         '(a b (a 2 b) c 1 2 (D b (a s 4 2) c 1 2 a) a)
         #'(lambda (x) (or (equal 1 x) (equal x 'a)))))

Here's a short example of one way to approaching the problem. Read the comments.

Upvotes: 2

Dan D.
Dan D.

Reputation: 74685

Maybe like this:

(defun elimina (x l &optional l0)
  (cond ((null l) (reverse l0))
        ((eq x (car l)) (elimina x (cdr l) l0))
        (T (elimina x (cdr l) (cons (if (not (atom (car l))) 
                                        (elimina x (car l)) 
                                        (car l))
                                     l0)))))

Upvotes: 0

Related Questions