如何获取clojure中嵌套结构中给定键的所有值 [英] How to get all values for a given key in a nested structure in clojure

查看:191
本文介绍了如何获取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]而不使用任何全局绑定。

Need to find out all values for the key :uid In this case answer should return [1 2 11 12 13] without using any global bindings. Needs solution scale for any level of nested structure.

感谢

推荐答案

这可以使用tree-seq和过滤器,或与post-walk。这两种评价对我都很有趣:

This can be done with tree-seq and filter, or with post-walk. Both appraoches are interesting to me:

tree-seq:

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删除重复项)时,看起来更好。

Which looks better when threaded out with ->> (and with set and vec to remove 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:

or with 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的键,它将它附加到一个本地原子。然后在结尾返回原子的累积内容。这与您的示例稍有不同,因为它累积了重复。如果你想有效地消除它们,那么使用一个集合作为累加器而不是一个向量,然后在结束时将它转换成一个向量一次(你的例子有一个向量)

This walks the structure with a function that, if the structure contains a key named :uid, appends it to a local atom. Then at the end return the accumulated contents of the atom. This differs slightly from your example because it accumulates duplicates. If you want to eliminate them efficiently then use a set as the accumulator instead of a vector, then turn it into a vector once at the end (your example has results 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]

这篇关于如何获取clojure中嵌套结构中给定键的所有值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆