Fork me on GitHub
#clojure
<
2023-03-04
>
kwladyka22:03:16

Does someone have ready function with good performance to get all leaves from tree (map and vectors where leaf is always a map)?

{:a [{:a 1} {:b 2}]
 :b [{:a 1} {:b [{:a 1}]}]}
Should return
[{:a 1} {:b 2} {:a 1} {:a 1}]
Of course the tree is much more complex, but only maps and vectors and all leaves are map.

p-himik22:03:09

If you're already using Specter in that project, I suspect it will give good performance here. But coming up with the right selector might be a tad tricky.

kwladyka22:03:54

so far pure Clojure (no extra libraries for tree)

kwladyka22:03:26

I will read about Specter

lilactown00:03:38

I'd start with something naive like this

(defn leaf?
  [x]
  (and (map? x) (not (some coll? (vals x)))))

(defn leaves
  [x]
  (cond
    (leaf? x) [x]
    (map? x) (mapcat leaves (vals x))
    (vector? x) (mapcat leaves x)))

(leaves {:a [{:a 1} {:b 2}]
         :b [{:a 1} {:b [{:a 1}]}]})
;; => ({:a 1} {:b 2} {:a 1} {:a 1})

lilactown00:03:24

you could then optimize it a bit further by only checking for map? and vals once

(defn leaves
  [x]
  (cond
    (map? x) (or (seq (mapcat leaves (vals x))) [x])
    (vector? x) (mapcat leaves x)))

lilactown00:03:38

I'd start there and then start getting into specter or other weird stuff only if that was too slow

Hendursaga17:03:38

I'll second using Specter. It's awesome. Otherwise look into tree-seq, I suppose.