在clojure中,我怎样才能像这样转换嵌套地图:
(def parent {:id "parent-1"
:value "Hi dude!"
:children [{:id "child-11"
:value "How is life?"
:children [{:id "child-111"
:value "Some value"
:children []}]}
{:id "child-12"
:value "Does it work?"
:children []}]})
进入这个:
[
[{:id "parent-1", :value "Hi dude!"}]
[{:id "parent-1", :value "Hi dude!"} {:id "child-11", :value "How is life?"}]
[{:id "parent-1", :value "Hi dude!"} {:id "child-11", :value "How is life?"} {:id "child-111", :value "Some value"}]
[{:id "parent-1", :value "Hi dude!"} {:id "child-12", :value "Does it work?"}]
]
我在非常愚蠢的递归尝试中磕磕绊绊,现在我的大脑被烧毁了。
到目前为止我所得到的是以下内容。它确实可以获得正确的数据,但是它会将数据放入一些额外的不需要的嵌套向量中。
如何解决这个问题? 在Clojure中有一个很好的惯用方法吗?
感谢。
(defn do-flatten [node parent-tree]
(let [node-res (conj parent-tree (dissoc node :children))
child-res (mapv #(do-flatten % node-res) (:children node))
end-res (if (empty? child-res) [node-res] [node-res child-res])]
end-res))
(do-flatten parent [])
产生:
[
[{:id "parent-1", :value "Hi dude!"}]
[[
[{:id "parent-1", :value "Hi dude!"} {:id "child-11", :value "How is life?"}]
[[
[{:id "parent-1", :value "Hi dude!"} {:id "child-11", :value "How is life?"} {:id "child-111", :value "Some value"}]
]]]
[
[{:id "parent-1", :value "Hi dude!"} {:id "child-12", :value "Does it work?"}]
]]
]
答案 0 :(得分:2)
我不知道这是否是惯用的,但似乎有用。
(defn do-flatten
([node]
(do-flatten node []))
([node parents]
(let [path (conj parents (dissoc node :children))]
(vec (concat [path] (mapcat #(do-flatten % path)
(:children node)))))))
您可以在致电时暂停[]
。
答案 1 :(得分:0)
另一种选择是使用拉链:
width: 5em
答案 2 :(得分:0)
我倾向于使用一些本地状态来简化逻辑:
(defn do-flatten
([node]
(let [acc (atom [])]
(do-flatten node [] acc)
@acc))
([node base acc]
(let [new-base (into base (self node))]
(swap! acc conj new-base)
(doall
(map #(do-flatten % new-base acc) (:children node))))))
也许一些功能纯粹主义者不喜欢它,当然你可以以纯粹的功能方式完成整个事情。我的感觉是,它是一个临时的,完全是本地的一个状态(因此不会导致状态臭名昭着的问题),所以如果它具有更高的可读性(我认为它)我真的很高兴使用它。