问题
Say we have the following list:
(A B C D)
We can find the index of C
with:
(position 'C '(A B C D))
If, however one of the list elements is nested with its own children:
(position 'B '(A (B 1 2 (3 x y z)) C D))
The function would yield NIL
.
How do we effectively locate the nth
position of elements within a nested list like this, especially if the atom is located within a sub-list like, for example, y
?
-----
Here's my attempt thus far:
(setq lst (A (B 1 2 (3 x y z)) C D))
(defun top-level-elm (lst)
(loop for x from 0 to (- (length lst) 1)
collect (car (nth x lst))))
(defun elm-id (elm lst)
(position elm (top-level-elm lst)))
(defun child-of (elm lst)
(cdr (nth (elm-id elm lst) lst)))
(defun child-id (lst)
(loop for x from 0 to (- (length lst) 1)
collect (child-of (nth x (top-level-elm lst)))))
回答1:
It is not really clear what should be the position when the element is found in some deep level of the tree.
One possibility is to return the index of the n-th leaf corresponding to the element.
In this case, for instance, given a flatten function, you could write a function like this:
(defun my-position (elm tree)
(position elm (flatten tree))
Another possibility is to generalize the concept of index to a tree structure, for instance by returning a list in which the element in position j is the position of the element or the list containing it at level j. For instance:
(my-position 'A '(A (B 1 2 (3 x y z)) C D)) => (0)
(my-position 'B '(A (B 1 2 (3 x y z)) C D)) => (1 0)
(my-position 'y '(A (B 1 2 (3 x y z)) C D)) => (1 3 2)
In this case, a recursive function could be:
(defun my-position (elm tree &optional (start 0))
"find the generalized position of elm inside tree.
Parameters: elm - element to be found
tree - a list of atoms and lists in which to search the element
start - the tentative position"
(cond ((null tree) nil) ; element not present => nil
((atom (first tree)) ; if the first element is an atom, then
(if (eql elm (first tree)) ; if equal to element, found
(list start) ; return position start
;; otherwise, recur on rest of list incrementing the tentative position
(my-position elm (rest tree) (1+ start))))
;; otherwise, the first element is a list,
;; try to find it inside, with a recursive call
(t (let ((pos (my-position elm (first tree) 0)))
(if pos ; if not nil the element has been found
(cons start pos) ; return the current position followed by the position inside the list
; otherwise recur on rest of list incrementing the tentative position
(my-position elm (rest tree) (1+ start)))))))
Final note: to write a more “professional” function one should add the keyword parameters of the predefined position function.
来源:https://stackoverflow.com/questions/58618184/lisp-position-of-nested-list-element-with-children