LISP function to remove nils

試著忘記壹切 提交于 2020-03-19 04:31:48

问题


I want to write a function in LISP that will completely remove all NILS in a list. The list may be nested, meaning it can contain other lists inside. For example the list '((state L L L L) NIL (state L L R L) NIL) should be tranformed into '((STATE L L L L) (STATE L L R L)).


回答1:


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

Works for your example:

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

And with nested lists:

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

But watch out:

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



回答2:


Paul Graham calls this function (recurring into sublists remove-if) "prune" in On Lisp, p. 49. It is one of the utility functions.

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



回答3:


A generic function in the style of 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))))))

Examples:

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



回答4:


(defun remove-if-nil (list) (remove-if-not 'identity list))

remove-if-not takes a predicate and a list, and removes all the items in the list that do not satisfy the predicate, that is, that return nil when evaluated in the predicate. identity, as you can guess, returns exactly the same thing it takes, so (remove-if-not 'identity list) removes every element in list that is nil.



来源:https://stackoverflow.com/questions/3967320/lisp-function-to-remove-nils

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!