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

Lisp: list of nodes on a given level k

我想从一棵树中找到位于给定级别 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 and k=2,我应该得到结果:(g d f),但相反,我得到一些错误说 "A is not of type LIST"。有谁知道如何修复我的代码?提前致谢!

这是您的 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)。它 returns 是一个空列表,因此最后一个例子中的 append 将丢弃它。实际上返回想要的原子是由第二种情况处理的。
  • 我用的是标准 remove-if 而不是你的 atoms。对 complement 的调用产生一个匹配任何非原子的谓词。因此 remove-if 只保留原子。您也可以使用 remove-if-not 并省略 complement,但这已被弃用。
  • 在最后一个例子中,我使用 (reduce #'append ...) 创建了一个简单的原子列表。 编辑:将其更改为使用 mapcan

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