I am trying to print tree elements in Pre Order (Root, Left and Right) in Clojure for a given tree structure.
Below is the code prints the elements in Pre order, but I am not able to figure out how to apply the condition to check that the string ends with "ire".
I tried using Filter and When as well. Can someone help here please?
(defn preorder [tree]
(if (nil? (:root tree))
(str nil)
(let [v (:root tree)
l (:left tree)
r (:right tree)]
(str v
(str " ")
(str l (str " ") (preorder l))
(str " ")
(str r (str " ")(preorder r))))))
Suggestions:
Algorithm: Generate a sequence of :root values walking the tree.
Use the sequence library, map or filter, to convert it into strings
or filter the nodes as need be.
Data: Use nil values for :left and :right instead of for
:root.
Thus:
(defn preorder [tree]
(if tree
(let [v (:root tree)
l (:left tree)
r (:right tree)]
(cons v (concat (preorder l) (preorder r))))))
For example
(preorder {:root 5, :left {:root 10}})
;(5 10)
(filter even? (preorder {:root 5, :left {:root 10}}))
;(10)
Beware that you will run out of stack if your tree is too deep.
Related
For a given tree I would like to sum the depth of each node and calculate that recursively (so not with map/flatten/sum).
Is there a way to do that with recur or do I need to use a zipper in this case?
recur is for tail recursion, meaning if you could do it with normal recursion, where the return value is exactly what a single recursive call would return, then you can use it.
Most functions on trees cannot be written in a straightforward way when restricted to using only tail recursion. Normal recursive calls are much more straightforward, and as long as the tree depth is not thousands of levels deep, then normal recursive calls are just fine in Clojure.
The reason you may have found recommendations against using normal recursive calls in Clojure is for cases when the call stack could grow to tens or hundreds of thousands of calls deep, e.g. a recursive call one level deep for each element of a sequence that could be tens or hundreds of thousands of elements long. That would exceed the default maximum call stack depth limits of many run-time systems.
Using normal stack consuming recursion you can accomplish this pretty easily, by doing a depth-first traversal and summing the depth on the way back out.
(defn sum-depths
([tree]
(sum-depths tree 0))
([node depth]
(if-not (vector? node)
depth
(do
(apply
+
(for [child-node (second node)]
(sum-depths child-node (inc depth))))))))
(sum-depths [:root
[:a1
[:b1
[:a2 :b2]]
:c1]])
;; => 6
(sum-depths ["COM"
[["B"
[["C"
[["D"
[["E"
["F"
["J"
[["K"
["L"]]]]]]
"I"]]]]
["G"
["H"]]]]]])
;; => 19
The details depend a little bit on how you model your tree, so the above assumes that a node is either a vector pair where the first element is the value and the second element is a vector of children nodes, or if it is a leaf node then it's not a vector.
So a leaf node is anything that's not a vector.
And a node with children is a vector of form: [value [child1 child2 ...]
And here I assumed you wanted to sum the depth of all leaf nodes. Since I see from your answer, that your example gives 42, I'm now thinking you meant the sum of the depth of every node, not just leaves, if so it only takes one extra line of code to do so:
(defn sum-depths
([tree]
(sum-depths tree 0))
([node depth]
(if-not (vector? node)
depth
(do
(apply
+
depth
(for [child-node (second node)]
(sum-depths child-node (inc depth))))))))
(sum-depths [:root
[:a1
[:b1
[:a2 :b2]]
:c1]])
;; => 7
(sum-depths ["COM"
[["B"
[["C"
[["D"
[["E"
["F"
["J"
[["K"
["L"]]]]]]
"I"]]]]
["G"
["H"]]]]]])
;; => 42
And like your own answer showed, this particular algorithm can be solved without a stack as well, by doing a level order traversal (aka breadth-first traversal) of the tree. Here it is working on my tree data-structure (similar strategy then your own answer otherwise):
(defn sum-depths [tree]
(loop [children (second tree) depth 0 total 0]
(if (empty? children)
total
(let [child-depth (inc depth)
level-total (* (count children) child-depth)]
(recur (into [] (comp (filter vector?) (mapcat second)) children)
child-depth
(+ total level-total))))))
(sum-depths [:root
[:a1
[:b1
[:a2 :b2]]
:c1]])
;; => 7
(sum-depths ["COM"
[["B"
[["C"
[["D"
[["E"
["F"
["J"
[["K"
["L"]]]]]]
"I"]]]]
["G"
["H"]]]]]])
;; => 42
And for completeness, I also want to show how you can do a depth-first recursive traversal using core.async instead of the function call stack in order to be able to traverse trees that would cause a StackOverFlow otherwise, but still using a stack based recursive depth-first traversal instead of an iterative one. As an aside, there exists some non stack consuming O(1) space depth-first traversals as well, using threaded trees (Morris algorithm) or tree transformations, but I won't show those as I'm not super familiar with them and I believe they only work on binary trees.
First, let's construct a degenerate tree of depth 10000 which causes a StackOverFlow when run against our original stack-recursive sum-depths:
(def tree
(loop [i 0 t [:a [:b]]]
(if (< i 10000)
(recur (inc i)
[:a [t]])
t)))
(defn sum-depths
([tree]
(sum-depths tree 0))
([node depth]
(if-not (vector? node)
depth
(do
(apply
+
depth
(for [child-node (second node)]
(sum-depths child-node (inc depth))))))))
(sum-depths tree)
;; => java.lang.StackOverflowError
If it works on your machine, try increasing 10000 to something even bigger.
Now we rewrite it to use core.async instead:
(require '[clojure.core.async :as async])
(defmacro for* [[element-sym coll] & body]
`(loop [acc# [] coll# ~coll]
(if-let [~element-sym (first coll#)]
(recur (conj acc# (do ~#body)) (next coll#))
acc#)))
(def tree
(loop [i 0 t [:a [:b]]]
(if (< i 10000)
(recur (inc i)
[:a [t]])
t)))
(defn sum-depths
([tree]
(async/<!! (sum-depths tree 0)))
([node depth]
(async/go
(if-not (vector? node)
depth
(do
(apply
+
depth
(for* [child-node (second node)]
(async/<!
(sum-depths child-node (inc depth))))))))))
;; => (sum-depths tree)
50015001
It is relatively easy to rewrite a stack-recursive algorithm to use core.async instead of the call stack, and thus make it so it isn't at risk of causing a StackOverFlow in the case of large inputs. Just wrap it in a go block, and wrap the recursive calls in a <! and the whole algorithm in a <!!. The only tricky part is that core.async cannot cross function boundaries, which is why the for* macro is used above. The normal Clojure for macro crosses function boundaries internally, and thus we can't use <! inside it. By rewriting it to not do so, we can use <! inside it.
Now for this particular algorithm, the tail-recursive variant using loop/recur is probably best, but I wanted to show this technique of using core.async for posterity, since it can be useful in other cases where there isn't a trivial tail-recursive implementation.
i would also propose this one, which is kinda straightforward:
it uses more or less the same approach, as tail recursive flatten does:
(defn sum-depth
([data] (sum-depth data 1 0))
([[x & xs :as data] curr res]
(cond (empty? data) res
(coll? x) (recur (concat x [:local/up] xs) (inc curr) res)
(= :local/up x) (recur xs (dec curr) res)
:else (recur xs curr (+ res curr)))))
the trick is that when you encounter the collection at the head of the sequence, you concat it to the rest, adding special indicator that signals the end of branch and level up. It allows you to track the current depth value. Quite simple, and also using one pass.
user> (sum-depth [1 [2 7] [3]])
;;=> 7
user> (sum-depth [1 2 3 [[[[[4]]]]]])
;;=> 9
You can use map/mapcat to walk a tree recursively to produce a lazy-seq (of leaf nodes). If you need depth information, just add it along the way.
(defn leaf-seq
[branch? children root]
(let [walk (fn walk [lvl node]
(if (branch? node)
(->> node
children
(mapcat (partial walk (inc lvl))))
[{:lvl lvl
:leaf node}]))]
(walk 0 root)))
To run:
(->> '((1 2 ((3))) (4))
(leaf-seq seq? identity)
(map :lvl)
(reduce +))
;; => 10
where the depths of each node are:
(->> '((1 2 ((3))) (4))
(leaf-seq seq? identity)
(map :lvl))
;; => (2 2 4 2)
Updates - sum all nodes instead of just leaf nodes
I misread the original requirement and was assuming leaf nodes only. To add the branch node back is easy, we just need to cons it before its child sequence.
(defn node-seq
"Returns all the nodes marked with depth/level"
[branch? children root]
(let [walk (fn walk [lvl node]
(lazy-seq
(cons {:lvl lvl
:node node}
(when (branch? node)
(->> node
children
(mapcat (partial walk (inc lvl))))))))]
(walk 0 root)))
Then we can walk on the hiccup-like tree as before:
(->> ["COM" [["B" [["C" [["D" [["E" [["F"] ["J" [["K" [["L"]]]]]]] ["I"]]]]] ["G" [["H"]]]]]]]
(node-seq #(s/valid? ::branch %) second)
(map :lvl)
(reduce +))
;; => 42
Note: above function uses below helper specs to identify the branch/leaf:
(s/def ::leaf (s/coll-of string? :min-count 1 :max-count 1))
(s/def ::branch (s/cat :tag string? :children (s/coll-of (s/or :leaf ::leaf
:branch ::branch))))
Here's my alternative approach that does use recur:
(defn sum-of-depths
[branches]
(loop [branches branches
cur-depth 0
total-depth 0]
(cond
(empty? branches) total-depth
:else (recur
(mapcat (fn [node] (second node)) branches)
(inc cur-depth)
(+ total-depth (* (count branches) cur-depth))))))
(def tree ["COM" (["B" (["C" (["D" (["E" (["F"] ["J" (["K" (["L"])])])] ["I"])])] ["G" (["H"])])])])
(sum-of-depths [tree]) ; For the first call we have to wrap the tree in a list.
=> 42
You can do this using the Tupelo Forest library. Here is a function to extract information about a tree in Hiccup format. First, think about how we want to use the information for a simple tree with 3 nodes:
(dotest
(hid-count-reset)
(let [td (tree-data [:a
[:b 21]
[:c 39]])]
(is= (grab :paths td) [[1003]
[1003 1001]
[1003 1002]])
(is= (grab :node-hids td) [1003 1001 1002])
(is= (grab :tags td) [:a :b :c])
(is= (grab :depths td) [1 2 2])
(is= (grab :total-depth td) 5) ))
Here is how we calculate the above information:
(ns tst.demo.core
(:use tupelo.forest tupelo.core tupelo.test)
(:require
[schema.core :as s]
[tupelo.schema :as tsk]))
(s/defn tree-data :- tsk/KeyMap
"Returns data about a hiccup tree"
[hiccup :- tsk/Vec]
(with-forest (new-forest)
(let [root-hid (add-tree-hiccup hiccup)
paths (find-paths root-hid [:** :*])
node-hids (mapv xlast paths)
tags (mapv #(grab :tag (hid->node %)) node-hids)
depths (mapv count paths)
total-depth (apply + depths)]
(vals->map paths node-hids tags depths total-depth))))
and an example on a larger Hiccup-format tree:
(dotest
(let [td (tree-data [:a
[:b 21]
[:b 22]
[:b
[:c
[:d
[:e
[:f
[:g 7]
[:h
[:i 9]]]]]]
[:c 32]]
[:c 39]])]
(is= (grab :tags td) [:a :b :b :b :c :d :e :f :g :h :i :c :c])
(is= (grab :depths td) [1 2 2 2 3 4 5 6 7 7 8 3 2])
(is= (grab :total-depth td) 52)))
Don't be afraid of stack size for normal processing. On my computer, the default stack doesn't overflow until you get to a stack depth of over 3900 recursive calls. For a binary tree, just 2^30 is over a billion nodes, and 2^300 is more nodes than the number of protons in the universe (approx).
I need to Develop a function called bounds which takes a nested list of numbers as its only argument (ie: a tree). Bounds should return the largest &smallest value in the tree. Eg:
(bounds '(1 (-2 17 (4) -8 (-6 13) (-8 17))))
Using clojure and not using the flatten function but using recursion to visit each node
(defn maxv [tree]
(cond
(number? tree) tree
(tree? tree)
(let [newmax (maxv (first tree)) ]
;;let newmax be the first in the tree
(if (< newmax (maxv (first (rest tree))))
;; if the next in the tree is smaller
(= (newmax (maxv (first (rest tree)))))
;;change newmax to this
(recur (maxv (rest tree)))))
;; recur through the rest
this is what i have i think i am being too java ish
flatten is very efficient, so there is no benefit in implementing it yourself.
If your nested list is not too big, you could apply (juxt min max) directly to the flattened list:
(defn bounds [coll]
(apply (juxt min max) (flatten coll)))
For large input collections I would recommend using reduce instead of apply:
(defn bounds [coll]
(reduce (fn [[minv maxv :as res] v]
(if res [(min minv v) (max maxv v)] [v v]))
nil
(flatten coll)))
If you really need pure recursive implementation, here is an example for you:
(defn bounds [coll]
(loop [coll coll [minv maxv :as res] nil]
(if-let [[h & ts] (seq coll)]
(if (sequential? h)
(recur (concat h ts) res)
(recur ts (if res [(min minv h) (max maxv h)] [h h])))
res)))
All three implementation will yield you a tuple containing min and max values:
(bounds '(1 (-2 17 (4) -8 (-6 13) (-8 17)))) ; => [-8 17]
Update: note on sum-tree implementation from comments
It's a very bad idea to use multiple recursion in your code, because it'll blow your stack very quickly:
(sum-tree (range 7000)) ; => java.lang.StackOverflowError
Try using tail recursion with recur, or higher-order functions instead:
(defn sum-tree [tree]
(if (number? tree)
tree
(reduce + (map sum-tree tree))))
This question already has answers here:
How can I get the nested keys of a map in clojure?
(11 answers)
Closed 8 years ago.
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.
(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.
(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).
`
I'm try to writemy own "walk through tree" function, but I'm new in FP
I've wrote these function and it works nice, but it looks ugly
(defrecord Tree [value left right])
(defn depth_walk_tree
[tree functor]
(let [item (functor (:value tree))]
(let [leftlst
(if (:left tree)
(cons item (depth_walk_tree (:left tree) functor))
(list item))
]
(if (:right tree)
(concat
leftlst
(depth_walk_tree (:right tree) functor))
leftlst))))
(def tree (Tree. 1 (Tree. 2 (Tree. 0 nil nil) (Tree. 90 nil nil)) (Tree. 3 nil (Tree. 10 nil nil)) ))
(println (depth_walk_tree tree #(+ % 1) ))
Programs answer is
(2 3 1 91 4 11); is Ok
Can anyone advise me how make it beauty?
PS Sorry for my writing mistakes. English in not my native language.
This looks a bit more functional, IMHO:
(defn depth_walk_tree [tree functor]
(concat
(list (functor (:value tree)))
(if (:left tree) (depth_walk_tree (:left tree) functor))
(if (:right tree) (depth_walk_tree (:right tree) functor))))
And it preserves the original result, too:
(depth_walk_tree tree inc)
=> (2 3 1 91 4 11)
How can I create a Clojure zipper for a TRIE, represented by nested maps, were the keys are the letters.?
Something like this:
{\b {\a {\n {\a {\n {\a {'$ '$}}}}}} \a {\n {\a {'$ '$}}}}
Represents a trie with 2 words 'banana' and 'ana'. (If necessary , its possible to make some changes here in maps..)
I've tried to pass map? vals assoc as the 3 functions to the zipper,respectively.
But it doesnt seem to work..
What 3 functions should I use?
And how the insert-into-trie would look like based on the zipper ?
map? vals #(zipmap (keys %1) %2) would do but doesn't support insertion/removal of children (since children are only values, you don't know which key to remove/add).
The map-zipper below does support insertion/removal because nodes are [k v] pairs (except the root which is a map).
(defn map-zipper [m]
(z/zipper
(fn [x] (or (map? x) (map? (nth x 1))))
(fn [x] (seq (if (map? x) x (nth x 1))))
(fn [x children]
(if (map? x)
(into {} children)
(assoc x 1 (into {} children))))
m))
The solution proposed by #cgrant is great, but implicitly describes a tree where all branches and leaf nodes have an associated value (the key in the dictionary) except for the root node that is just a branch without a value.
So, the tree {"/" nil}, is not a tree with a single leaf node, but a tree with an anonymous root branch and a single leaf node with value /.
In practice, this means that every traversal of the tree has to first execute a (zip/down t) in order to descend the root node.
An alternative solution is to explicitly model the root inside the map, that is, only create zippers from maps with a single key at the root. For example: {"/" {"etc/" {"hosts" nil}}}
The zipper can then be implemented with:
(defn map-zipper [map-or-pair]
"Define a zipper data-structure to navigate trees represented as nested dictionaries."
(if (or (and (map? map-or-pair) (= 1 (count map-or-pair))) (and (= 2 (count map-or-pair))))
(let [pair (if (map? map-or-pair) (first (seq map-or-pair)) map-or-pair)]
(zip/zipper
(fn [x] (map? (nth x 1)))
(fn [x] (seq (nth x 1)))
(fn [x children] (assoc x 1 (into {} children)))
pair))
(throw (Exception. "Input must be a map with a single root node or a pair."))))