这是我对这个问题的看法,也许你会发现它很有用:
(defun depth-first-search (tree searched &optional comparator)
"TREE is the nested list of elements to search, SEARCHED
is the element to search for, COMPARATOR is the function used
to compare elements of the tree to the searched element, if
you don't provide any, then `equal' is used.
Returns a list of subscripts to be used with `nth' to find the
searched element. If the result is `nil', the list itself
is the searched element. If the result is not a list,
the `not-found' symbol, then the element was not found."
(unless comparator (setq comparator #'equal))
(let ((operations 'not-found))
(labels ((%df-search
(item ops)
(if (funcall comparator item searched)
(setq operations (reverse ops))
(let ((offset 0))
(when (consp item)
(dolist (i item)
(%df-search i (cons offset ops))
(unless (eq operations 'not-found)
(return))
(incf offset)))))))
(%df-search tree nil)
operations)))
(defun nth-repeat (subscripts tree)
"Given the list of SUBSCRIPTS, will subsequently evaluate
`nth' with every subscript on the result of the previous evaluation
such as to find the element in the TREE."
(let ((result tree))
(dolist (i subscripts result)
(setq result (nth i result)))))
(nth-repeat
(depth-first-search '(1 (1 1 2) (1 1 1 3)) 3)
'(1 (1 1 2) (1 1 1 3)))
它需要您使用cl
,但这很常见,您可能甚至不会注意到,您很可能已经拥有它。
编辑:好的,这样你可以避免完全查看不正确列表的最后一个元素,但是,这意味着你也不能在那里搜索:
(defun depth-first-search (tree searched &optional comparator)
"TREE is the nested list of elements to search, SEARCHED
is the element to search for, COMPARATOR is the function used
to compare elements of the tree to the searched element, if
you don't provide any, then `equal' is used.
Returns a list of subscripts to be used with `nth' to find the
searched element. If the result is `nil', the list itself
is the searched element. If the result is not a list,
the `not-found' symbol, then the element was not found."
(unless comparator (setq comparator #'equal))
(let ((operations 'not-found))
(labels ((%df-search
(item ops)
(if (funcall comparator item searched)
(setq operations (reverse ops))
(let ((offset 0))
(when (consp item)
(block outer
(maplist
(lambda (x)
(%df-search (car x) (cons offset ops))
(when (or (not (eq operations 'not-found))
(not (listp (cdr x))))
(return-from outer))
(incf offset))
item)))))))
(%df-search tree nil)
operations)))
(defun nth-repeat (subscripts tree)
"Given the list of SUBSCRIPTS, will subsequently evaluate
`nth' with every subscript on the result of the previous evaluation
such as to fint the element in the TREE."
(let ((result tree))
(dolist (i subscripts result)
(setq result (nth i result)))))
(defvar my-list '(((partnum . 1)
(1.1 (type (TEXT . plain)) (body (charset UTF-8))
(disposition nil) (transfer-encoding 7BIT))
(1.2 (type (TEXT . html)) (body (charset UTF-8))
(disposition nil) (transfer-encoding 7BIT))
(type . alternative) (body (boundary e89a8fb2067eba300404c63c5f7f))
(disposition nil) (transfer-encoding nil))
((partnum . 1.1) (type (TEXT . plain)) (body (charset UTF-8))
(disposition nil) (transfer-encoding 7BIT))
((partnum . 1.2) (type (TEXT . html)) (body (charset UTF-8))
(disposition nil) (transfer-encoding 7BIT))
((partnum . 2) (type (IMAGE . x-xpixmap)) (body (name ladybug.xpm))
(disposition nil) (transfer-encoding BASE64))))
(depth-first-search
my-list '(charset UTF-8)) ; (0 1 2 1)
(nth-repeat
(depth-first-search
my-list '(charset UTF-8)) my-list) ; (charset UTF-8)
可能,这不是解决问题的最佳方法,但更好的解决方案需要更改算法以记录car
s 和cdr
s 的序列,从而将您带到有问题的元素。在这种情况下,您还可以在列表的“不当”部分进行搜索。但现在为时已晚:) 也许明天。
编辑 2:
(defun tree-to-proper-tree (tree)
(cond
((null tree) nil)
((consp tree)
(let ((head
(if (consp (car tree))
(tree-to-proper-tree (car tree))
(car tree))))
(cons head
(tree-to-proper-tree (cdr tree)))))
(t (list tree))))
(defun find-path-to (tree node &optional comparator)
(unless comparator (setq comparator #'equal))
(let ((operations 'not-found))
(labels ((%df-search
(item ops)
(if (funcall comparator item node)
(setq operations (reverse ops))
(when (consp item)
(%df-search (car item) (cons 'car ops))
(%df-search (cdr item) (cons 'cdr ops))))))
(%df-search tree nil)
operations)))
(defun c*r-path (path tree)
(dolist (i path tree)
(setq tree (funcall i tree))))
(defvar my-list '(((partnum . 1)
(1.1 (type (TEXT . plain)) (body (charset UTF-8))
(disposition nil) (transfer-encoding 7BIT))
(1.2 (type (TEXT . html)) (body (charset UTF-8))
(disposition nil) (transfer-encoding 7BIT))
(type . alternative) (body (boundary e89a8fb2067eba300404c63c5f7f))
(disposition nil) (transfer-encoding nil))
((partnum . 1.1) (type (TEXT . plain)) (body (charset UTF-8))
(disposition nil) (transfer-encoding 7BIT))
((partnum . 1.2) (type (TEXT . html)) (body (charset UTF-8))
(disposition nil) (transfer-encoding 7BIT))
((partnum . 2) (type (IMAGE . x-xpixmap)) (body (name ladybug.xpm))
(disposition nil) (transfer-encoding BASE64))))
(tree-to-proper-tree my-list) ; the same lists as above but made into a proper lists
(c*r-path (find-path-to my-list 'UTF-8) my-list) ; UTF-8
(c*r-path (find-path-to my-list 'plain) my-list) ; plain
好的,所以,在这里tree-to-proper-tree
,如果您选择它,它将以所有不正确的子树都将成为正确树的方式转换树。或者,您可以使用find-path-to
查找什么序列car
并将cdr
您带到您搜索的元素,c*r-path
并将评估该序列以返回以这种方式记录的元素。
请注意,以这种方式搜索相同节点的重复出现将非常具有挑战性。您必须提供一些比较器功能来计算找到该项目的次数。