1

I have to define a function filter that has as arguments a predicate and a list and returns as value the initial list with THE ONLY ATOMS -for every level of depth- which satisfy the initial predicate (keeping attention at NIL value in order to mantain the list structure).

Example:

(filter 'evenp '(24 5 (7) d (((4))) 3 ()))

(24 () (((4))) ())

The code i was thinking is like this:

(defun filter (pred list)
  (cond ((null list) nil)
        ((funcall pred (car list))
         (cons (car list)
               (filter pred (cdr list))))
        (T (filter pred (cdr list)))))

How can i implement the depth fact, keeping so the round bracket as displayed in the example?

thank you all

Fred_2
  • 249
  • 2
  • 11
  • You need to check if the first element is a list and then do something. – Rainer Joswig Jan 05 '18 at 16:21
  • 1
    You need to first check if the car of your list is an atom or not. Then decide to do something – Dan Robertson Jan 05 '18 at 16:45
  • 2
    [Since you are operating on the _tree_, not _list_ (you say "for every level of depth"), you should treat `car` and `cdr` identically](https://stackoverflow.com/a/47759265/850781) – sds Jan 05 '18 at 17:27

1 Answers1

2

Here is a possible solution:

(defun filter (predicate x)
   (if (consp x)  ; if x is a cons, that is a tree:
       (let ((ca (car x))
             (cd (filter predicate (cdr x)))) ; filter always the cdr
         (if (listp ca)                       ; if the car of x is a list (nil or cons)
             (cons (filter predicate ca) cd)  ; then filter also the car
             (if (funcall predicate ca) (cons ca cd) cd))) ; car is a non-nil atom!
       x))        ; if x is a atom (nil or the last cdr of an improper list), return x

CL-USER> (filter 'evenp '(24 5 (7) 5 (((4))) 3 ()))
(24 NIL (((4))) NIL)
Renzo
  • 26,848
  • 5
  • 49
  • 61