grace9
grace9

Reputation: 87

How to remove a list of length 1 from a nested list in lisp?

I have a nested list (1 (4 (5) 3) 9 10) and I want to delete the lists of length 1 so the result would be (1 (4 3) 9 10). This is what I have tried so far, which does not remove (5) and returns the original list.

(defun remove (l)
(cond
    ((null l) nil)   
    ((and (listp (car l)) (= (length l) 1)) (remove (cdr l)))   
    ((atom (car l)) (cons (car l) (remove (cdr l))))
    (T (cons (remove (car l)) (remove (cdr l))))   
))

Upvotes: 1

Views: 136

Answers (2)

Gwang-Jin Kim
Gwang-Jin Kim

Reputation: 9950

Tail call recursive version. Plus: Without the test (atom (car l)) to be permissive for non-list and non-atom components in the list. (e.g. vectors or other objects as element of the list - they are treated like atoms.

(defun my-remove (l &optional (acc '()))
  (cond ((null l) (nreverse acc))
        ((listp (car l)) (if (= 1 (length (car l)))         ;; list objects
                             (my-remove (cdr l) acc)        ;; - of length 1     
                             (my-remove (cdr l) (cons (my-remove (car l)) acc)))) ;; - longer
        (t (my-remove (cdr l) (cons (car l) acc)))))        ;; non-list objects

Upvotes: 0

Leo
Leo

Reputation: 1934

Two things: first, remove is a predefined function in package CL, so I strongly advice to use a different name, let's say my-remove. Second, you are testing the length of l instead of the sublist (car l), which is what you want to eliminate. The correct form would be:

(defun my-remove (l)
  (cond
    ((null l) nil)   
    ((and (listp (car l)) (= (length (car l)) 1)) (my-remove (cdr l)))   
    ((atom (car l)) (cons (car l) (my-remove (cdr l))))
    (T (cons (my-remove (car l)) (my-remove (cdr l))))   
))

Upvotes: 2

Related Questions