Повторение дочерних элементов в иерархии объектов в Clojure - PullRequest
1 голос
/ 21 июня 2020

У меня следующая проблема:

(def relations1 
  '((child-of peter carl) 
    (child-of carl herb)

    (peter x 0 y 0 age 6) 
    (carl  x 1 y 1 age 36) 
    (herb  x 2 y 2 age 66)))

Если родитель перемещается, ребенок перемещается на такое же расстояние, поэтому, если в новых отношениях указано, что herb и peter переместились, тогда я хочу обновить детей, которых нет в отношении Relations2, с тем же смещением, но тех, которые присутствуют, я оставлю их в покое. Итак, на следующем этапе:

(def relations2 
  '((herby2 x 3 y 2.5 age 66) 
    (pete2  x 0 y 0   age 6)))

Сначала я сопоставил Relations1 с отношениями в Relations2:

(def matches 
  '( ((herb x 2 y 2 age 66) 
      (herb2 x 3 y 2.5 age 66)), 

     ((peter x 0 y 0 age 6)
      (peter2 x 0 y 0 age 6))))

Я хочу go через сопоставленные, обновить свои собственные новые позиции (сохраняя свои прежние имена и возраст) и рекурсивно проверьте, есть ли у них дети, чтобы также обновить свои позиции. Я пробовал это, но в значительной степени застрял в том, как рекурсировать и для детей:

(def update-parents [matches, relations1]
(loop [rest matches
       all relations1
       result ()]
 (if (empty? rest)
     result
     (let [[head & others] rest
            r1 (first head)
            r2 (second head)
            exists (map first r2)
            children (map second (filter #(and (= (first r1) (last %)) (= 'child-of (first %))) all))] 
          (if (some #(= (first r1) %) exists)
               (recur others (concat (update r1 r2) (recur ???)); if it is already there, update position and its children's
               ; if it's not there, then ignore

) 

Итак, конечный результат должен быть таким

(def result 
  '((herb  x 3 y 2.5 age 66)
    (peter x 0 y 0   age 6) 
    (carl  x 2 y 1.5 age 36) ))

У меня две основные проблемы:

  1. children возвращает список дочерних элементов, поэтому мне нужно отфильтровать отношения1 по тем, которые находятся в этом списке
  2. как мне повторить для дочерних элементов? мне нужно использовать другой l oop?

1 Ответ

1 голос
/ 21 июня 2020

Вы можете удалить элементы из списка (т. Е. Создать новый список без этих элементов), поместив элементы, подлежащие удалению, в набор и используя (remove #(contains? the-set %) the-list) или, что более идиоматично, (remove the-set the-list) потому что набор работает как функция. («Фильтрация» работает аналогично, но сохраняет вещи, с которыми согласуется предикат.)

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

В любом случае, если вы хотите использовать рекурсию любого вида, вам нужна древовидная структура данных, в которой каждый узел похож на root. С «мешком фактов» в relation1 будет сложно работать.

Обратите внимание на clojure.walk и clojure.zip как стандартные решения для древовидных структур данных.

PS Это может также помогать работать с REPL «снизу вверх», работая с ингредиентами до запекания.

...