0

The Program is supposed to find each symbol in the List, that comes after a certain symbol. The function gets to parameters passed in. A List which could contain nested-lists and a symbol. The function has to scan thru the list and search for the given symbol and print the symbols that come after the given symbol.

Examples:

(find-all 'a '((b a) ((c a b)))) --> (c b)
 (find-all 'a '(b (a a) c)) --> (a c)
 (find-all 'a '(b d c e)) --> nil

My Code So Far:

(defun find-all (a list)
    (if (consp list)
        (if (consp (car list))
            (find-all a (car list))
        (if (eq a (car list))
            (cons (car(cdr list)) (find-all a(cdr list)))
            (find-all a(cdr list))))))

This code works except when the symbol its looking for is the last atom in the list. it fails in these test cases:

 (find-all 'a '((b a) ((c a b)))) --> (c b)
 (find-all 'a '(b (a a) c)) --> (a c)

but works fine in these cases:

(find-all 'a '(b a c a e)) --> (c e)

The issue is probably at my cons statement and i am unable to fix this.

Mark
  • 3
  • 1
  • 1
    Use a common lisp implementation with good debugging facilities (e.g. [SBCL](http://sbcl.org/) or perhaps [Clisp](http://www.clisp.org/)...) and learn how to use these debugging facilities. BTW, Lisp usually uses *expressions*, not *statements* – Basile Starynkevitch Nov 02 '14 at 20:11
  • The issue is that after i identify the symbol in the list. I look for the symbol next to it in the list, but if the symbol is the last one in the list there is no symbol next to it its an empty list which is why it returns Nil. – Mark Nov 02 '14 at 20:13
  • So learn how to use the debugging facilities at your disposal. – Basile Starynkevitch Nov 02 '14 at 20:14
  • Wouldn't `(find-all 'a '((b a) ((c a b))))` be `(c a b)`? – uselpa Nov 02 '14 at 20:24
  • @uselpa it should be (c b) only the immediate symbol that follows the given symbol must be returned. – Mark Nov 02 '14 at 20:31

1 Answers1

0

I don't think your code is correct. First of all, it's not correctly indented, which makes it difficult to read. The correct indentation should be:

(defun find-all (a list)
  (if (consp list)
      (if (consp (car list))
          (find-all a (car list))
          (if (eq a (car list)) ; if properly intended here
              (cons (car(cdr list)) (find-all a(cdr list)))
              (find-all a(cdr list)))))))))

Even after that I have trouble following your logic. For example, when something is a cons, then you should process both the car and the cdr, but you don't. I didn't go through the the debugging process, but you should.


Instead, I'd like to show you an alternative. I would suggest splitting the problem in 2 parts:

flattening the list

Since we start with a nested list but end up with a flat list, it's easier to flatten the list first. Here is a classical flatten function:

(defun flatten (sxp)
  (labels
   ((sub (sxp res)
      (cond
       ((null sxp)  res)
       ((consp sxp) (sub (car sxp) (sub (cdr sxp) res)))
       (t           (cons sxp res)))))
   (sub sxp nil)))

processing the flat list

Now, with a flat list, the rest becomes obvious, using the member function (and calling my function find-from to distinguish it from yours at the REPL):

(defun find-from (a lst)
  (labels
      ((sub (lst)
         (when lst
           (let ((rst (cdr (member a lst))))
             (when rst
               (cons (car rst) (sub rst)))))))
    (sub (flatten lst))))

testing

? (find-from 'a '((b a) ((c a b))))
(C B)
? (find-from 'a '(b (a a) c))  
(A C)
? (find-from 'a '(b d c e)) 
NIL
? (find-from 'a '(b a c a e)) 
(C E)
uselpa
  • 18,732
  • 2
  • 34
  • 52