Removing from nested lists - lisp

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)

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)

combo DrRacket implicit else

Why does this work?
(define (rev l)
(cond ((null? l) l)
(else (append (rev(cdr l)) (list (car l))))))
Output:
> (rev L1)
(d c b a)
and this not?
(define (rev l)
(cond ((null? l) l)
(append (rev(cdr l)) (list (car l)))))
Output:
> (rev L1)
(a)
Isn't "else" implicit in Lisp?
In the second example the procedure append is the predicate and since it is a procedure and every value except #f is true it does the consequent (rev (cdr l))
cond has to have its terms in parentheses. There is no explicit else, thought if neither predicate matches the implementation can choose the result (undefined value).
if is a different conditional that perhaps is better suited in this case.
(define (rev l)
(if (null? l)
l
(append (rev (cdr l))
(list (car l)))))
Changing the indentation makes it easier to see what happens:
(define (rev l)
(cond
[(null? l) l]
[else (append (rev(cdr l)) (list (car l)))]))
(define (rev l)
(cond
[(null? l) l]
[append (rev(cdr l))
(list (car l))]))
Note that in the second version you have a clause
[append (rev(cdr l))
(list (car l))]))
When the cond-expression is evaluated it tries to evaluate each left hand side until it finds one that gives a non-false value. Here the left-hand side append evaluates to the append function, which is a non-false value.
The next thing that happens, is the right hand side is evaluated. Due to an implicit begin on the right hand side, this is evaluated:
(begin
(rev(cdr l))
(list (car l)))
To conclude: You accidentally wrote an expression that had correct syntax, but meant something different than you expected.
Note that the error is easier to spot, if you use square brackets around the clauses in the cond. (The square brackets [] and the standard () mean the same).

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

Confusion with sublists

I ran over an example of a problem which should determine the list of all non-numeric atoms at any level in a non-linear list.
(Defun Lis(L)
(Cond
((Null L) Nil)
((Not (Numberp (Car L))) (Cons (Car L) (Lis (Cdr L))))
((Atom (Car L)) (Lis (Cdr L)))
(T (Append (Lis (Car L)) (Lis (Cdr L))))
))
I took an example, (Lis '(1 A ((B) 6) (2 (C 3)) D 4)) which should return (A B C D)
Now I don't understand how can the list be created when the 3rd element of the list is evaluated ((B) 6).It will enter on the 2nd branch and do the cons?But that isn't constructing the new list with ((B) 6)?When will it enter on the last branch? I'm a little confused of how this algorithm works,can somebody make it clear for me?
The code works fine if you "invert" the 2 middle tests:
(defun lis(L)
(cond
((null L) nil)
((numberp (car L)) (lis (cdr L)))
((atom (car L)) (cons (car L) (lis (cdr L))))
(t (append (lis (car L)) (lis (cdr L))))))
because (not (numberp (car L))) is also true for lists so in the initial version the code never recurses down into a sublist.
I would write it as:
(defun tree-keep-if (predicate tree)
"Returns the list of all non-numeric atoms at any level in a cons tree."
(mapcan (lambda (item)
(cond ((consp item) (tree-keep-if predicate item))
((funcall predicate item) (list item))
((atom item) nil)))
tree))
Using it:
CL-USER > (tree-keep-if (complement #'numberp) '(1 A ((B) 6) (2 (C 3)) D 4))
(A B C D)
A more sophisticated version might remove the recursion to not be limited by stack size.

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