編集#2:この質問と調査全体は、ジッパーの基本的な概念が欠けていることに基づいていました。特定のノードの観点から、データ構造のパースペクティブを表すこと。したがって、zipper は常に、現在のノードと、そのノードから見たツリーの残りの部分のペアです。私は当初、ジッパーからまったく新しい構造を生成しようとしていましたが、必要なのはジッパー自体だけでした。他の誰かがそれによって助けられることを期待して、これはすべて後世に残します(または、後継者への警告として機能します!)。
元の質問:
ジッパーを使って木を操作しようとしています。具体的な問題は、任意のツリー内の任意の基準に一致する 2 つのノード間のルートを実行時に生成する必要があることです。
path
この関数を使用して、現在の場所を呼び出すことで場所へのルートを取得できると考えpath
ました。しかし、返されたパスは、そこに到達するために必要な最後のステップを省略しているようです。
例えば:
(def test-zip (vector-zip [0 [1] [2 [3 [4] 5 [6 [7] [8]]]]]))
(-> test-zip
down right right down
right down right right
node)
を与えます5
が、
(-> test-zip
down right right down
right down right right
path)
与える
[[0 [1] [2 [3 [4] 5 [6 [7] [8]]]]] [2 [3 [4] 5 [6 [7] [8]]]] [3 [4] 5 [6 [7] [8]]]]
これは同じ場所ではありません (最後の 3 つのステップの効果がありませんdown right right
)。
パス関数は、あなたと実際の場所の間の兄弟を無視して、ツリー内の親の場所にのみ到達するようです。
path
関数のポイントを見逃していますか?ツリーとパスが与えられた場合、パスをツリーに適用すると、部分的にではなく、パスの元の場所に移動すると想定していました。
UPDATE :次の関数定義を使用して、開始場所から終了場所までのノードのパスをコンパイルしました。
(defn lca-path [start-loc end-loc]
(let [sczip (z/root start-loc)
start-path (z/path start-loc)
start-node (z/node start-loc)
end-path (z/path end-loc)
end-node (z/node end-loc)
lca-path (filter (set start-path) end-path)
lca-node [(last lca-path)]
lca-to-start (conj (vec (drop (count lca-path) start-path)) start-node)
lca-to-end (conj (vec (drop (count lca-path) end-path)) end-node)
]
(concat (reverse lca-to-start) lca-node lca-to-end))
)
@Mark Fisher とのチャットにかなり影響を受けました。ありがとうございます!