LISP - removing an element from a list with nested lists - lisp

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.

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.

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)))))

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.

Related

Delete element from a nested list while keeping the original nested structure CLISP [duplicate]

I've got a homework assignment that has stumped me! I have to create a function goo(A L) that will remove every A in L and it has to work on nested lists also.
Here's what I've got so far
(defun goo(A L)
(cond ((null L) nil) ; if list is null, return nil
(T ; else list is not null
(cond ((atom (car L))) ;if car L is an atom
((cond ((equal A (car L)) (goo A (cdr L))) ;if car L = A, call goo A cdr L
(T (cons (car L) (goo A (cdr L)))))) ;if car L != A,
(T (cons (goo A (car L)) (goo A (cdr L)))))) ;else car L is not atom, call goo on car L and call goo on cdr L
))
This function returns True no matter what I give it.
You parens are messed up. Move the last paren around (atom (car L)) to include the next cond expression. I suggest using an IDE which shows matching parens.
As for styling, if you didn't know, cond can accept multiple clauses. This way you don't need to have the t and then the cond again. You can also use 'if' if you are only testing a single predicate and making a decision based solely on that.
Note: this was originally posted as an edit to the question by the original asker in revision 2.
I tried another approach and it's working now.
(defun goo(A L)
(cond ((null L) nil)
((atom (car L)) (cond ((equal A (car L)) (goo A (cdr L)))
(T (cons (car L) (goo A (cdr L))))))
(T (cons (goo A (car L)) (goo A (cdr L))))
))
Note 2: this should conventionally be formatted like this to show the program structure:
(defun goo (a l)
(cond ((null l) nil)
((atom (car l))
(cond ((equal a (car l))
(goo a (cdr l)))
(t (cons (car l)
(goo a (cdr l))))))
(t (cons (goo a (car l))
(goo a (cdr l))))))
I think it might be easier to look at this a replacement into trees problem. It's easy to define a function that takes a tree and replaces subtrees in it that satisfy a test. There's a standard function subst-if that does that, but it replaces every matching subtree with the same thing. It will be more useful to us if we replace the element with a value computed from the subtree:
(defun %subst-if (new test tree)
"Replace subtrees of TREE that satisfy TEST with the result
of calling NEW with the subtree."
(cond
;; If tree satifies the test, return (new tree).
((funcall test tree)
(funcall new tree))
;; If tree is a cons, recurse.
((consp tree)
(cons (%subst-if new test (car tree))
(%subst-if new test (cdr tree))))
;; Otherwise, just return the leaf.
(tree)))
With this, its easy to define the kind of function we need. When an element X appears somewhere in a nested list structure, it means that there is a cons cell whose car is X. We want to replace that cons cell with its cdr, but to also recurse on the cdr of the cell. This isn't hard:
(defun replace* (x list &key (test 'eql))
"Remove occurrences of X in LIST and its sublists."
(%subst-if
(lambda (cons)
"Replace elements of the form (X . more) with
(replace* x more :test test)."
(replace* x (cdr cons) :test test))
(lambda (subtree)
"Detect subtrees of the form (X . more)."
(and (consp subtree)
(funcall test x (car subtree))))
list))
(replace* 'a '(1 a (2 a 3) a 4 a 5))
;=> (1 (2 3) 4 5)

Flattening lists (while removing 'nil' and keeping atoms after " . ") in lisp

I want to create a function that would flatten a list and remove all potential nil inside.
Expected behavior, example 1:
(myfunc '(a (b (c) (d)) (e f) (g (h)) nil)) => (a b c d e f g h)
Expected behavior, example 2:
(myfunc '(a . d)) => (a d)
my function so far:
(defun myfunc (l)
(cond
((atom l) nil)
((and (atom (car l)) (not (equal (car l) nil))) (cons (car l) (myfunc (cdr l))))
(t (append (myfunc (car l)) (myfunc (cdr l))))))
My function works as expected for the first example, but not the second.
I get:
(myfunc '(a . d)) => (a)
Why doesn't it keep that d?
Is there a way to fix it?
Perhaps you should think about what the flatten function should do, in plain English:
Base case: If flattening nil, return an empty list.
Base case: If flattening single atoms, return a list containing just that.
Recursive case: If flattening pairs, return a list appending the flattening of its car with the flattening of its cdr.
Here's how I'd implement the description I just gave:
(defun flatten (x)
(cond ((null x) x)
((atom x) (list x))
(t (nconc (flatten (car x)) (flatten (cdr x))))))

Removing from nested lists

I've got a homework assignment that has stumped me! I have to create a function goo(A L) that will remove every A in L and it has to work on nested lists also.
Here's what I've got so far
(defun goo(A L)
(cond ((null L) nil) ; if list is null, return nil
(T ; else list is not null
(cond ((atom (car L))) ;if car L is an atom
((cond ((equal A (car L)) (goo A (cdr L))) ;if car L = A, call goo A cdr L
(T (cons (car L) (goo A (cdr L)))))) ;if car L != A,
(T (cons (goo A (car L)) (goo A (cdr L)))))) ;else car L is not atom, call goo on car L and call goo on cdr L
))
This function returns True no matter what I give it.
You parens are messed up. Move the last paren around (atom (car L)) to include the next cond expression. I suggest using an IDE which shows matching parens.
As for styling, if you didn't know, cond can accept multiple clauses. This way you don't need to have the t and then the cond again. You can also use 'if' if you are only testing a single predicate and making a decision based solely on that.
Note: this was originally posted as an edit to the question by the original asker in revision 2.
I tried another approach and it's working now.
(defun goo(A L)
(cond ((null L) nil)
((atom (car L)) (cond ((equal A (car L)) (goo A (cdr L)))
(T (cons (car L) (goo A (cdr L))))))
(T (cons (goo A (car L)) (goo A (cdr L))))
))
Note 2: this should conventionally be formatted like this to show the program structure:
(defun goo (a l)
(cond ((null l) nil)
((atom (car l))
(cond ((equal a (car l))
(goo a (cdr l)))
(t (cons (car l)
(goo a (cdr l))))))
(t (cons (goo a (car l))
(goo a (cdr l))))))
I think it might be easier to look at this a replacement into trees problem. It's easy to define a function that takes a tree and replaces subtrees in it that satisfy a test. There's a standard function subst-if that does that, but it replaces every matching subtree with the same thing. It will be more useful to us if we replace the element with a value computed from the subtree:
(defun %subst-if (new test tree)
"Replace subtrees of TREE that satisfy TEST with the result
of calling NEW with the subtree."
(cond
;; If tree satifies the test, return (new tree).
((funcall test tree)
(funcall new tree))
;; If tree is a cons, recurse.
((consp tree)
(cons (%subst-if new test (car tree))
(%subst-if new test (cdr tree))))
;; Otherwise, just return the leaf.
(tree)))
With this, its easy to define the kind of function we need. When an element X appears somewhere in a nested list structure, it means that there is a cons cell whose car is X. We want to replace that cons cell with its cdr, but to also recurse on the cdr of the cell. This isn't hard:
(defun replace* (x list &key (test 'eql))
"Remove occurrences of X in LIST and its sublists."
(%subst-if
(lambda (cons)
"Replace elements of the form (X . more) with
(replace* x more :test test)."
(replace* x (cdr cons) :test test))
(lambda (subtree)
"Detect subtrees of the form (X . more)."
(and (consp subtree)
(funcall test x (car subtree))))
list))
(replace* 'a '(1 a (2 a 3) a 4 a 5))
;=> (1 (2 3) 4 5)

Issue using cons function in Lisp?

I am learning Lisp and I had to write a function whose return value was a list containing the odd integers (if any) from the given input. In code I have this:
(defun f3 (a)
(cond
((null a) nil )
((and (numberp (car a)) (oddp (car a))) (cons (car a) (f3 (cdr a))))
(T (f3 (cdr a)))
) ; end cond
)
I originally wanted to use the append function, but I kept getting errors.
It was recommended to me to use cons function. When I did this my function started working (code is above). I originally had this:
(defun f3 (a)
(cond
((null a) ())
((and (numberp (car a)) (oddp (car a))) (append (f3 (cdr a)) (car a))))
(T (append () (f3 (cdr a))))
)
)
but kept getting errors. For example, if I called (f3 '(1 2 3)) it would say "error 3 is not type LIST". So, my questions are why does cons work here and why did append not work? How does cons work? Thanks in advance.
append wants list arguments, and (car a) is not a list. Instead of (car a) you'd need (list (car a)). In other words, (append (f3 (cdr a)) (list (car a))).
That will basically work, but you'll get the result in reverse order. So that should be (append (list (car a)) (f3 (cdr a))).
Also note that your (append () (f3 (cdr a))) is equivalent to just (f3 (cdr a)).
The resulting changes in your original would be:
(defun f3 (a)
(cond
((null a) ())
((and (numberp (car a)) (oddp (car a)))
(append (list (car a)) (f3 (cdr a)))))
(T (f3 (cdr a)))))
But, you wouldn't normally use append to prepend a single element to a list. It would more naturally be done using cons. So
(append (list (car a)) (f3 (cdr a)))
Is more appropriately done by:
(cons (car a) (f3 (cdr a)))
Which finally takes you right to the working version you showed.
While something like mbratch's answer will help you in learning about list manipulation (and so is probably a more useful answer for you at this point in your study), it's also important to learn about the standard library of the language that you're using. In this case, you're trying to filter out everything except odd numbers. Using remove-if-not, that's just:
(defun keep-odd-numbers (list)
(remove-if-not (lambda (x)
(and (numberp x) (oddp x)))
list))
CL-USER> (keep-odd-numbers '(1 a 2 b 3 c 4 d 5 e))
;=> (1 3 5)
While this isn't a fix to your actual problem, which #mbratch provided, here's the way I would implement something like this using the LOOP macro (another part of the standard library):
(defun keep-odd-numbers (list)
(loop for x in list collecting x when (and (numberp x) (oddp x))))

Reverse LISP list in place

I would like to write a function that reverses the elements of a list, but it should happen in place (that is, don't create a new reversed list).
Something like:
>> (setq l ' (a b c d))
((a b c d)
>> (rev l)
(d c b a)
>> l
(d c b a)
What flags should I follow to achieve this?
Have a look at nreverse which will modify the list in place (see HyperSpec).
As per the comments, do note the comments that #Barmar made and this bit from the spec:
For nreverse, sequence might be destroyed and re-used to produce the result. The result might or might not be identical to sequence. Specifically, when sequence is a list, nreverse is permitted to setf any part, car or cdr, of any cons that is part of the list structure of sequence.
It's not difficult to implement this (ignoring fault cases). The keys are to use (setf cdr) to reuse a given cons cell and not to lose the reference to the prior cdr.
(defun nreverse2 (list)
(recurse reving ((list list) (rslt '()))
(if (not (consp list))
rslt
(let ((rest (cdr list)))
(setf (cdr list) rslt)
(reving rest list)))))
(defmacro recurse (name args &rest body)
`(labels ((,name ,(mapcar #'car args) ,#body))
(,name ,#(mapcar #'cadr args))))
[edit] As mentioned in a comment, to do this truly in-place (and w/o regard to consing):
(defun reverse-in-place (l)
(let ((result l))
(recurse reving ((l l) (r (reverse l))
(cond ((not (consp l)) result)
(else (setf (car l) (car r))
(reving (cdr l) (cdr r)))))))
> (defvar l '(1 2 3))
> (reverse-in-place l))
(3 2 1)
> l
(3 2 1)