问题
I wanted to get key-chains of a tree, from every root to every leave.
for example input tree:
{"b" {:term true}, "a" {"y" {:term true}, "x" {:term true}}}
I was expecting output:
(("b" :term) ("a" "x" :term) ("a" "y" :term)) or ["b" "ax" "ay"]
I've figured out a tail-recursion, it worked fine:
(defn down-strings [trie]
"this one works. 80msecs for address.txt, not bad at all"
(lazy-seq
(loop [strings [],trie trie]
(if (empty? trie) strings
(let [[k v] (first trie)]
(recur (if (:term v) (conj strings k) strings)
(reduce
conj
(rest trie)
(map (fn [[dk dv]] [(str k dk) dv]) (dissoc v :term)))))))))
Now I have trouble with my recursive practice:
(defn down-strings [trie]
(if (map? trie)
(map (fn [[k v]] (conj (down-strings v) k)) trie)
[]))
the output is :
(("b" [:term]) ("a" ("y" [:term]) ("x" [:term])))
I tried everything I could, couldn't fix this.
回答1:
(defn down-strings [trie]
(mapcat
(fn [[k v]]
(if (map? v) (map (partial str k) (down-strings v)) [""]))
trie))
For example,
(down-strings {"b" {:term true}, "a" {"y" {:term true}, "x" {:term true}}})
;("ax" "ay" "b")
I expect this to be quite a bit slower than @noisesmith's solution.
回答2:
(defn down-strings
([trie] (down-strings trie []))
([trie prefix]
(if (map? trie)
(mapcat (fn [[k v]]
(down-strings v (conj prefix k)))
trie)
[prefix])))
A recursive solution is easier with an extra argument representing the accumulated state of each branch taken, and the usage of mapcat
ensures that each path is one sequence, instead of deep nesting of sequences (an extra level of nesting per term in the path).
`
来源:https://stackoverflow.com/questions/25268818/get-key-chains-of-a-tree-in-clojure