This can be done using tree-seq and a filter, or with subsequent processing. I am very interested in both ratings:
trail tree:
user> (map :uid (filter #(if (and (map? %) (:uid %)) true false) (tree-seq #(or (map? %) (vector? %)) identity threads))) (1 2 1 1 2 13 12 12 11 12)
Which looks better when used ->> (and with installation and vec to remove duplicates)
user> (->> (tree-seq #(or (map? %) (vector? %)) identity threads) (filter #(if (and (map? %) (:uid %)) true false)) (map :uid) set vec) [1 2 11 12 13]
or using postwalk:
user> (let [results (atom [])] (clojure.walk/postwalk #(do (if-let [uid (:uid %)] (swap! results conj uid)) %) threads) @results) [1 2 1 1 2 13 12 12 11 12]
This scans the structure using a function that, if the structure contains a key with the name: uid, adds it to the local atom. Then at the end we return the accumulated contents of the atom. This is slightly different from your example because it accumulates duplicates. If you want to eliminate them effectively, use a vector as a set instead, and then turn it into a vector once at the end (your example has a result in a vector)
user> (let [results (atom #{})] (clojure.walk/postwalk #(do (if-let [uid (:uid %)] (swap! results conj uid)) %) threads) (vec @results)) [1 2 11 12 13]
Arthur ulfeldt
source share