Lisp:给定级别k上的节点列表

时间:2016-02-13 12:28:34

标签: list lisp common-lisp levels

我想找到树中的所有原子,它们位于给定的k级。我试过像:

(defun atoms (l)
  ;returns the list of atoms of l at its superficial level
  (cond
    ((null l) l)
    ((or (atom l) (numberp l)) l)
    ((or (atom (car l)) (numberp (car l))) 
      (append (list(car l)) (atom (cdr l))))
    (T (atoms (Cdr l)))))

(defun findat (l pos k)
  (cond
    ((null l) l)
    ((= k pos) (atoms l))
    ((and (or (atom l) (numberp l)) (= k pos)) l)
    (T (cons '() (mapcar #'(lambda (l) (findat l (+ pos 1) k)) l)))))

所以,对于样本: l =(a(b(g))(c(d(e))(f))),pos = 0和k = 2 ,我应该得到结果:(gdf),但我得到一些错误,说“A不是LIST类型”。有谁有任何想法,如何修复我的代码?提前谢谢!

1 个答案:

答案 0 :(得分:3)

以下是findat的某种修改版本。你可能想要为这个函数想一个更好的名字(至少写出来(find-atoms)而不是不必要的缩写)。

(defun findat (l k)
  "Find atoms on level K in list L."
  (cond
    ((atom l) '())
    ((= k 0) (remove-if (complement #'atom) l))
    (t (mapcan #'(lambda (l)
                   (findat l (1- k)))
               l))))

(findat '(a (b (g)) (c (d (e)) (f))) 2)
; => (G D F)

的变化:

  • 我删除了参数pos。使用k简单地倒计时更容易。
  • 我更改了第一个案例以检查原子(包括nil)。它返回一个空列表,以便最后一个案例中的append将丢弃它。实际上,返回想要的原子是由第二种情况处理的。
  • 我使用的是标准remove-if,而不是atoms。对complement的调用产生一个匹配任何非原子的谓词。因此remove-if只保留原子。您也可以使用remove-if-not并忽略complement,但已弃用。
  • 在最后一种情况下,我使用(reduce #'append ...)来创建原子的平面列表。 修改:将其更改为使用mapcan

另请注意我如何在函数的开头放置一个字符串。这是一个文档。你应该这样做,而不是像atoms那样在那里发表评论。这样您就可以使用(describe #'findat)查看文档(或者您可以使用Emacs / IDE查看文档)。