Положение Lisp вложенного элемента списка с потомками - PullRequest
0 голосов
/ 30 октября 2019

Скажем, у нас есть следующий список:

(A B C D)

Мы можем найти индекс C с помощью:

(position 'C '(A B C D))

Если, однако, один из элементов списка вложен ссобственные дочерние элементы:

(position 'B '(A (B 1 2 (3 x y z)) C D))

Функция выдаст NIL.

Как нам эффективно определить положение элементов nth во вложенном списке, например, особенно, если атом находится внутри подсписка, например, y?

-----

Вот моя попытка:

(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 Ответ

1 голос
/ 30 октября 2019

Не совсем понятно, какой должна быть позиция, когда элемент находится на каком-то глубоком уровне дерева.

Одна из возможностей - вернуть индекс n-го листа, соответствующего элементу.

В этом случае, например, учитывая функцию сглаживания , вы могли бы написать такую ​​функцию:

(defun my-position (elm tree)
  (position elm (flatten tree))

Другая возможность - обобщить понятие индексав древовидную структуру, например, путем возврата списка, в котором элемент в позиции j является позицией элемента или списка, содержащего его на уровне j. Например:

(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)

В этом случае рекурсивной функцией может быть:

(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)))))))

Последнее замечание: для написания более «профессиональной» функции необходимо добавить ключевые параметры параметрапредопределенная position функция .

...