Clojure - 递归半平坦嵌套地图

时间:2016-04-19 22:00:14

标签: clojure

在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?"}]
]]
]

3 个答案:

答案 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))))))

也许一些功能纯粹主义者不喜欢它,当然你可以以纯粹的功能方式完成整个事情。我的感觉是,它是一个临时的,完全是本地的一个状态(因此不会导致状态臭名昭着的问题),所以如果它具有更高的可读性(我认为它)我真的很高兴使用它。