我正在尝试创建一个从{node [children]}
形式的邻接列表构建树的函数。
(def adjacency
{nil [:a]
:a [:b :c]
:b [:d :e]
:c [:f]})
应该导致
{nil {:a {:b {:d nil
:e nil}
:c {:f nil}}}}
但是我试过了,我无法让它发挥作用。递归是我的一个弱点,我发现的大多数递归示例只处理列表上的递归,而不是树。
已编辑:由于在发布时没有编辑器和原始来源,原始数据集和结果无意中嵌套得太深。对不起。
答案 0 :(得分:2)
adjacency
中的每个子地图中只有一个条目。这有必要吗?结果tree
中存在同样的问题。
我希望更清楚:
(def adjacency {:a [:b :c]
:b [:d :e]
:c [:f]})
所以解决方案是:
(defn tree [m root]
(letfn [(tree* [l]
(if (contains? m l)
{l (into {} (map tree* (m l)))}
[l nil]))]
(tree* root)))
测试:
(tree adjacency :a)
=> {:a {:b {:d nil
:e nil}
:c {:f nil}}}
<强>更新即可。如果您不需要将结果树作为嵌套映射
(defn tree [m root]
(letfn [(tree* [l]
(if (contains? m l)
(list l (map tree* (m l)))
(list l nil)))]
(tree* root)))
(tree adjacency :a)
=> (:a ((:b ((:d nil)
(:e nil)))
(:c ((:f nil)))))
答案 1 :(得分:2)
在处理树时,我通常更喜欢使用clojure.walk
。
我假设根节点是adjacency
向量中的第一个。
(use 'clojure.walk)
(def adjacency
[{nil [:a]}
{:a [:b :c]}
{:b [:d :e]}
{:c [:f]}])
(prewalk
(fn [x]
(if (vector? x)
(let [[k v] x lookup (into {} adjacency)]
[k (into {} (map (fn [kk] [kk (lookup kk)]) v))])
x))
(first adjacency))
结果:{nil {:a {:b {:d {}, :e {}}, :c {:f {}}}}}
注意:空子代表{}
而不是nil
,子元素也是地图而不是矢量,因为地图可以很容易地导航到这棵树。