【问题标题】:LISP function to remove nilsLISP 函数删除 nil
【发布时间】:2010-10-19 10:17:13
【问题描述】:

我想在 LISP 中编写一个函数,该函数将完全删除列表中的所有 NILS。该列表可能是嵌套的,这意味着它可以包含其他列表。例如列表 '((state L L L L) NIL (state L L R L) NIL) 应转换为 '((STATE L L L L) (STATE L L R L))。

【问题讨论】:

  • 子列表中可以有NILs吗?如果是,它们是否也应该被删除?如果是,嵌套可以有多深?

标签: function lisp


【解决方案1】:
(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))

【讨论】:

    【解决方案2】:

    Paul Graham 在On Lisp, p. 中将此函数(重复到子列表中删除-if)称为“修剪”。 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))
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:
        (defun remove-if-nil (list) (remove-if-not 'identity list))
        

        remove-if-not 接受一个谓词和一个列表,并删除列表中所有不满足谓词的项目,即在谓词中评估时返回 nil 的项目。你可以猜到,identity 返回的结果完全相同,因此 (remove-if-not 'identity list) 会删除列表中所有为 nil 的元素。

        【讨论】:

        • 虽然此代码块可能会回答这个问题,但最好能提供一些解释说明为什么这样做。
        • 我添加了一个简短的解释,希望有助于澄清。
        • 这似乎无法处理问题所述的嵌套列表。
        猜你喜欢
        • 2021-12-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-15
        • 1970-01-01
        • 2018-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多