如何在没有map的情况下在Lisp中创建一个子列表?

时间:2015-05-13 06:48:17

标签: list recursion lisp sublist

我正在尝试创建一个函数,用于创建给定列表中所有子列表的列表。

我的意思是,当我有一个清单时:

(4 (a g b) g (1 2 3) g (4 5 6))

我想要一个清单:

((a g b) (1 2 3) (4 5 6))

目前我得到了什么:

(defun unterlisten_zurueckgeben (lst)
  (let (unterlisten)
    (cond ((endp lst) nil)
          ((listp (first lst))
           (or (unterlisten_zurueckgeben (first lst)) 
               (setq unterlisten (cons (first lst) (unterlisten_zurueckgeben (rest lst))))))
          (t (unterlisten_zurueckgeben (rest lst))))
    unterlisten))

似乎不起作用,我找不到我的错误。

2 个答案:

答案 0 :(得分:3)

如果是这样,你可以写:

(defun unterlisten-zurueckgeben (lst)
    (remove-if-not #'listp lst))
 ; or use #'consp if you don't want empty sublists

注意,在Lisp中,组合标识符的首选方法是使用破折号而不是下划线。

答案 1 :(得分:2)

所以你想只保留子列表。您可以使用remove-if轻松完成此操作:

(defun remove-atoms (lst)
  (remove-if #'atom lst))

在您的递归代码中存在以下问题:

(or (unterlisten_zurueckgeben (first lst)) 
    (setq unterlisten (cons (first lst) 
                            (unterlisten_zurueckgeben (rest lst))))))

如果(unterlisten_zurueckgeben (first lst))的结果不是空列表(例如带有列表的列表),那么它将是整个事物的结果。

如果它不是nil,那么您将本地绑定underlisten更改为看似正常的结果。

由于cond 不是尾部表达式。函数的结果总是underlisten。因此,对于您只是使用列表的其余部分递归的默认情况,结果永远不会返回,因为它将返回nilunderlisten的初始值)。

因此,即使您的递归滚动自己的解决方案也比它需要的复杂得多:

(defun remove-atoms (lst)
  (cond ((endp lst) nil)
        ((listp (first lst))
         (cons (first lst) (remove-atoms (rest lst))))
        (t (remove-atoms (rest lst)))))