(def threads
{:values
[{:_id "t1"
:u {:uid 1}
:members {:values [{:uid 1} {:uid 2}]}
:messages {:values
[{:_id "m1" :u {:uid 1}}
{:_id "m2" :u {:uid 2}}]}}
{:_id "t2"
:u {:uid 12}
:members {:values [{:uid 11} {:uid 12}]}
:messages {:values
[{:_id "m3" :u {:uid 13}}
{:_id "m4" :u {:uid 12}}]}}]})
Run Code Online (Sandbox Code Playgroud)
需要找出密钥的所有值:uid在这种情况下,答案应返回[1 2 11 12 13]而不使用任何全局绑定.需要任何级别的嵌套结构的解决方案规模.
谢谢
Art*_*ldt 10
这可以使用tree-seq和filter,或者使用post-walk完成.两个appraoches对我来说都很有趣:
树序列:
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)
Run Code Online (Sandbox Code Playgroud)
在使用->>(和使用set和vec删除重复项)时看起来更好看
user> (->> (tree-seq #(or (map? %) (vector? %)) identity threads)
(filter #(if (and (map? %) (:uid %)) true false))
(map :uid)
set
vec)
[1 2 11 12 13]
Run Code Online (Sandbox Code Playgroud)
或与邮差:
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]
Run Code Online (Sandbox Code Playgroud)
这将使用一个函数遍历结构,如果结构包含名为:uid的键,则将其附加到本地原子.然后在最后返回原子的累积内容.这与您的示例略有不同,因为它会累积重复项.如果你想有效地消除它们,那么使用一个集合作为累加器而不是一个向量,然后在结尾处将它变成一个向量(你的例子导致了一个向量)
user> (let [results (atom #{})]
(clojure.walk/postwalk
#(do (if-let [uid (:uid %)] (swap! results conj uid)) %)
threads)
(vec @results))
[1 2 11 12 13]
Run Code Online (Sandbox Code Playgroud)