clojure - 如何在clojure的嵌套结构中获取给定键的所有值

标签 clojure

(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}}]}}]})

需要找出键的所有值:uid
在这种情况下,答案应该返回 [1 2 11 12 13] 而不使用任何全局绑定(bind)。需要任何级别的嵌套结构的解决方案规模。

谢谢

最佳答案

这可以通过 tree-seq 和 filter 或 post-walk 来完成。这两种方法对我来说都很有趣:

树序列:

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) 

使用 ->> 穿出时看起来更好(并使用 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] 

或使用 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]

这将使用一个函数遍历结构,如果结构包含名为 :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]

关于clojure - 如何在clojure的嵌套结构中获取给定键的所有值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17332448/

相关文章:

clojure - 如何解构即时并从 java 时间库中提取年、月等

java - Storm redis spout元组无一异常(exception)地丢失

java - 使用 incanter 从 clojure 中的数组获取均值和协方差矩阵

java - 存储 Clojure(或 JVM)应用程序使用的文件的常规位置

string - 为什么split和join在clojure.string中的参数位置混合了?

machine-learning - 垃圾邮件分类器 Clojure

java - Clojure,反射 : Find classes that implement an interface

clojure - 自动刷新/自动重新加载资源

clojure - 为什么 Datomic 属性以驼峰命名

emacs - 如何在苹果酒模式下清除 REPL?