Tree 在common lisp中查找树中的项

Tree 在common lisp中查找树中的项,tree,common-lisp,Tree,Common Lisp,我正在尝试编写一个可以在树中查找项的函数,类似于序列的内置find函数。调用可能看起来像(在树项目树中查找:test test fn:key key-key fn)。hyperspec说传递给find的项可以是任何lisp对象(即“任何lisp数据”),但我想到的树不是通常的lisp二叉树。树,称之为multitree,是一个原子或列表的(可能是递归的或点的)列表。例如(在树中查找“(12)”(1(2)nil(3(12)).4):测试#'相等)=>(12)或一些非nil值 环顾四周,我发现了一些

我正在尝试编写一个可以在树中查找项的函数,类似于序列的内置
find
函数。调用可能看起来像
(在树项目树中查找:test test fn:key key-key fn)
。hyperspec说传递给
find
的项可以是任何lisp对象(即“任何lisp数据”),但我想到的树不是通常的lisp二叉树。树,称之为multitree,是一个原子或列表的(可能是递归的或点的)列表。例如
(在树中查找“(12)”(1(2)nil(3(12)).4):测试#'相等)
=>(12)或一些非nil值

环顾四周,我发现了一些有趣的代码,在这些代码中,经过适当的修改,似乎确实适用于标准cons树:

(defun find-in-tree (item tree &key (test #'eql))
  (catch 'find-in-tree
         (subst-if t (constantly nil) tree 
                   :key (lambda (element)
                          (when (funcall test element item)
                            (throw 'find-in-tree element))))
         nil))

但是,我不确定如何将其适应(或构建递归函数)于multitree。使用局部函数进行递归。一旦找到项目,就可以使用
return From
从中退出递归

CL-USER> (defun find-in-tree (item tree &key (test #'eql))                             
           (labels ((find-in-tree-aux (tree)                                           
                      (cond ((funcall test item tree)                                  
                             (return-from find-in-tree tree))                          
                            ((consp tree)                                              
                             (find-in-tree-aux (car tree))                             
                             (find-in-tree-aux (cdr tree))))))                         
             (find-in-tree-aux tree)))
FIND-IN-TREE                                                                           
CL-USER> (find-in-tree 3 '((2 (4 3)) 5))
3                                                                                      
CL-USER> (find-in-tree 12 '((2 (4 3)) 5))
NIL                                                                                    
CL-USER> (find-in-tree "foo" '(("bar" ("baz")) "foo") :test #'equalp)
"foo"                                                                   
CL-USER> (find-in-tree 6 '((2 (4 3 . 6)) 5))
6

节点作为树列表

CL-USER 1 > (defun find-in-tree (item tree &key (test #'eql) (key #'identity))
              (labels ((find-in-tree-aux (tree)                                   
                         (cond ((funcall test item (funcall key tree))
                                (return-from find-in-tree tree))
                               ((listp tree)
                                (mapc #'find-in-tree-aux tree)
                                nil))))
                (find-in-tree-aux tree)))
FIND-IN-TREE

像这样的。使用局部函数进行递归。一旦找到项目,就可以使用
return From
从中退出递归

CL-USER> (defun find-in-tree (item tree &key (test #'eql))                             
           (labels ((find-in-tree-aux (tree)                                           
                      (cond ((funcall test item tree)                                  
                             (return-from find-in-tree tree))                          
                            ((consp tree)                                              
                             (find-in-tree-aux (car tree))                             
                             (find-in-tree-aux (cdr tree))))))                         
             (find-in-tree-aux tree)))
FIND-IN-TREE                                                                           
CL-USER> (find-in-tree 3 '((2 (4 3)) 5))
3                                                                                      
CL-USER> (find-in-tree 12 '((2 (4 3)) 5))
NIL                                                                                    
CL-USER> (find-in-tree "foo" '(("bar" ("baz")) "foo") :test #'equalp)
"foo"                                                                   
CL-USER> (find-in-tree 6 '((2 (4 3 . 6)) 5))
6

节点作为树列表

CL-USER 1 > (defun find-in-tree (item tree &key (test #'eql) (key #'identity))
              (labels ((find-in-tree-aux (tree)                                   
                         (cond ((funcall test item (funcall key tree))
                                (return-from find-in-tree tree))
                               ((listp tree)
                                (mapc #'find-in-tree-aux tree)
                                nil))))
                (find-in-tree-aux tree)))
FIND-IN-TREE

你不应该使用
(或者(在树中查找…(汽车树)…)(在树中查找…(cdr树)…)
,(在搜索nil时有一些注意事项)是的,这修复了原子的问题,谢谢。你需要给出树的定义和一些实际的例子。否则我们只能猜测。此外,还不清楚您为什么不想检查CDR。只看汽车不会进行树遍历。你不应该使用
(或者(在树中查找…(汽车树)…)(在树中查找…(cdr树)…)
,(在搜索nil时有一些注意事项)是的,这可以修复原子,谢谢。你需要给出树的定义和一些实际的例子。否则我们只能猜测。此外,还不清楚您为什么不想检查CDR。只看这辆车就不需要遍历树。我现在更了解如何使用辅助功能了,谢谢。但是它仍然需要避免测试cdr:
(在树中查找“((23))”(1(23)):test#“equal)
=>((23))。这似乎与上面coredump的注释是同一个问题。@davypough在这种情况下,从
find In tree
中退出的返回值处于递归的第零级。这与通常从每个递归调用返回的情况不同,在这种情况下,结果必须传播回调用链,并且必须使用
手动切断搜索。希望这是清楚的。@daypough:对于一棵树来说,它做的事情是正确的。如果你想到了另一棵树,你需要定义一个节点是什么,它的内容是什么,它的继承者是什么。好吧,但是对一棵树的“cons-tree”解释对我来说似乎很不直观。在类似的序列操作中,
(find'((23))(1(23)):test#'equal)
=>NIL,((23))不是序列(1(23))的元素,而是树(1(23))的元素。然而,看起来我可以在树中找到(使用我的解释),使用aux函数只测试每棵树的汽车。然后,封闭的main函数将测试输入树的项相等性,然后将其转换为列表并将其传递给aux?@davypough您的参数是什么?一棵树还是一列树?您需要定义树以消除混淆。顺便说一句,cons树是简单的二叉树,cons单元作为节点,car和cdr作为后续节点。这很直观。我现在更了解如何使用辅助功能了,谢谢。但是它仍然需要避免测试cdr:
(在树中查找“((23))”(1(23)):test#“equal)
=>((23))。这似乎与上面coredump的注释是同一个问题。@davypough在这种情况下,从
find In tree
中退出的返回值处于递归的第零级。这与通常从每个递归调用返回的情况不同,在这种情况下,结果必须传播回调用链,并且必须使用
手动切断搜索。希望这是清楚的。@daypough:对于一棵树来说,它做的事情是正确的。如果你想到了另一棵树,你需要定义一个节点是什么,它的内容是什么,它的继承者是什么。好吧,但是对一棵树的“cons-tree”解释对我来说似乎很不直观。在类似的序列操作中,
(find'((23))(1(23)):test#'equal)
=>NIL,((23))不是序列(1(23))的元素,而是树(1(23))的元素。然而,看起来我可以在树中找到(使用我的解释),使用aux函数只测试每棵树的汽车。然后,封闭的main函数将测试输入树的项相等性,然后将其转换为列表并将其传递给aux?@davypough您的参数是什么?一棵树还是一列树?您需要定义树以消除混淆。顺便说一句,cons树是简单的二叉树,cons单元作为节点,car和cdr作为后续节点。这很直观。