且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-11-26 10:58:34

这可以使用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]