2010-10-19 14 views
4

Je veux écrire une fonction dans LISP qui supprimera complètement tous les NILS dans une liste. La liste peut être imbriquée, ce qui signifie qu'elle peut contenir d'autres listes à l'intérieur. Par exemple, la liste '((état L L L L) NIL (état L L R L) NIL) doit être transformée en' ((ÉTAT L L L L) (ÉTAT L L R L)).Fonction LISP pour supprimer nils

+2

Peut-il y avoir des «NIL» dans les sous-listes? Si oui, devraient-ils également être retirés? Si oui, à quelle profondeur peut aller la nidification? – Svante

Répondre

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

Works pour votre exemple:

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

Et avec des listes imbriquées:

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

Mais attention:

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

Une fonction générique dans le style de 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)))))) 

Exemples:

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

Paul Graham appelle cette fonction (récurrente dans les sous-listes remove-si) "pruneau" dans On Lisp, p. 49. C'est l'une des fonctions d'utilité.

(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-si-ne prend un prédicat et une liste, et supprime tous les éléments de la liste qui ne satisfont pas le prédicat, à savoir que nul de retour lors de l'évaluation dans le prédicat. l'identité, comme vous pouvez le deviner, renvoie exactement la même chose que cela, donc (remove-if-not 'liste d'identité) supprime tous les éléments de la liste qui est nulle.

+1

Bien que ce bloc de code puisse répondre à la question, il serait préférable que vous fournissiez des explications pour expliquer pourquoi. – DavidPostill

+0

J'ai ajouté une brève explication, j'espère que cela aide à clarifier. –

+0

Cela ne semble pas gérer les listes imbriquées comme l'indique la question. – blujay