2010-10-19 3 views
4

Я хочу написать функцию в LISP, которая полностью удалит все NILS в списке. Список может быть вложенным, то есть он может содержать другие списки внутри. Например, список '((состояние L L L L) NIL (состояние L L R L) NIL) должен быть преобразован в' ((STATE L L L L) (СОСТОЯНИЕ L L R L)).Функция LISP для удаления nils

+2

Может ли быть 'NIL' в подсписок? Если да, должны ли они также быть удалены? Если да, то насколько глубоко может гнездиться? – Svante

ответ

10
(defun remove-nil-recursively (x) 
    (if (listp x) 
    (mapcar #'remove-nil-recursively 
      (remove nil x)) 
    x)) 

Работы для вашего примера:

[1]> (remove-nil-recursively '((state L L L L) NIL (state L L R L) NIL)) 
((STATE L L L L) (STATE L L R L)) 

И с вложенными списками:

[2]> (remove-nil-recursively '(NIL (state L L nil R L) NIL)) 
((STATE L L R L)) 

Но берегитесь:

[3]> (remove-nil-recursively '(NIL (state L L (nil) R L) NIL)) 
((STATE L L NIL R L)) 
1

Обобщенная функция в стиле remove-if :

(defun remove-all (predic seq &optional res) 
    (if (null seq) 
     (reverse res) 
     (cond ((and (not (null (car seq))) (listp (car seq))) 
      (remove-all predic (cdr seq) 
         (cons (remove-all predic (car seq)) res))) 
      ((funcall predic (car seq)) 
      (remove-all predic (cdr seq) res)) 
      (t (remove-all predic (cdr seq) (cons (car seq) res)))))) 

Примеры:

> (remove-all #'null (list 1 2 'nil 3)) 
=> (1 2 3) 
> (remove-all #'null (list 1 2 'nil '(4 5 nil 6) 3)) 
=> (1 2 (4 5 6) 3) 
> (remove-all #'(lambda (x) (oddp x)) '(1 2 (3 4) 5 6 (7 8 (9 10)))) 
=> (2 (4) 6 (8 (10))) 
3

Пол Грэм называет эту функцию (повторяющейся в подсписки удалить, если) "чернослив" в On Lisp, стр. 49. Это одна из функций полезности.

(defun prune (test tree) 
    (labels ((rec (tree acc) 
       (cond 
       ((null tree) (nreverse acc)) 
       ((consp (car tree)) 
       (rec (cdr tree) 
        (cons (rec (car tree) nil) acc))) 
       (t (rec (cdr tree) 
         (if (funcall test (car tree)) 
          acc 
         (cons (car tree) acc))))))) 
    (rec tree nil))) 

(prune #'evenp '(1 2 (3 (4 5) 6) 7 8 (9))) 
(1 (3 (5)) 7 (9)) 
1
(defun remove-if-nil (list) (remove-if-not 'identity list)) 

удалить, если-не принимает предикат и список, и удаляет все элементы в списке, которые не удовлетворяют предикату, то есть, что возвращение ноль при оценке в предикате. идентичность, как вы можете догадаться, возвращает точно то же самое, что требуется, поэтому (remove-if-not 'identity list) удаляет каждый элемент в списке, который равен нулю.

+1

Хотя этот блок кода может ответить на вопрос, было бы лучше, если бы вы могли дать некоторое объяснение, почему оно это делает. – DavidPostill

+0

Я добавил краткое объяснение, надеюсь, это поможет прояснить. –

+0

Это, похоже, не относится к вложенным спискам в качестве заданного вопроса. – blujay