Lisp position of nested list element with children

偶尔善良 提交于 2020-03-05 04:35:29

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!