Reputation: 1608
I would like to write a function that given a possibly nested list would return me a list of the indexes of each leaf, such that I can reduce the list with nth and those indexes and obtain each leaf. Ex: Given lst = ((a b) c) it would return ((0 0) (0 1) (1)) because (reduce nth lst [0 0]) = a (reduce nth lst [0 1]) = b and (reduce nth lst [1]) = c.
EDIT: Here is my solution using clojure.zip. Anyone can come up with a more elegant one?
(defn tree-indexes [zipper matcher pos accumulator]
(loop [loc zipper pos pos accumulator accumulator]
(if (z/end? loc)
accumulator
(if (matcher (z/node loc))
(if (z/right loc)
(recur (z/next loc) (update-in pos [(- (count pos) 1)] inc) (conj accumulator [(z/node loc) pos]))
(if (z/end? (z/next loc))
(recur (z/next loc) pos (conj accumulator [(z/node loc) pos]))
(recur (z/next loc) (update-in (vec (butlast pos)) [(- (count (vec (butlast pos))) 1)] inc) (conj accumulator [(z/node loc) pos]))))
(recur (z/next loc) (conj pos 0) accumulator)))))
Upvotes: 1
Views: 196
Reputation: 6073
I have a (non-tail-)recursive solution but there probably is some kind of iterative approach:
(defn list-indices
([l] (list-indices l []))
([l parent-indices]
(->> l
(map-indexed
(fn [i element]
(let [indices (conj parent-indices i)]
(if (sequential? element)
(list-indices element indices)
[indices]))))
(apply concat))))
Upvotes: 1