【问题标题】:How to get all values for a given key in a nested structure in clojure如何在clojure的嵌套结构中获取给定键的所有值
【发布时间】:2013-06-27 00:04:10
【问题描述】:
(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] 而不使用任何全局绑定。需要任何级别的嵌套结构的解决方案规模。

谢谢

【问题讨论】:

    标签: clojure


    【解决方案1】:

    这可以通过 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 删除 dups)穿出时看起来更好

    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]
    

    【讨论】:

    • 谢谢亚瑟。我更喜欢 tree-seq 的答案。当我开始使用 clojure 时 - 我更喜欢 data-in->data-out 的步骤,而不是 atom 方法。今天学到了一些新东西-非常感谢:)
    • (map :uid (filter #(if (and (map? %) (:uid %)) true false) coll)) 可以只替换为 (keep :uid coll)
    • 哦,太棒了 :) 我更喜欢这样的外观。
    猜你喜欢
    • 2023-03-22
    • 2016-08-19
    • 2014-03-13
    • 1970-01-01
    • 2021-10-01
    • 2018-04-14
    • 2015-04-05
    • 2020-11-21
    • 1970-01-01
    相关资源
    最近更新 更多