2016-02-25 54 views
0

在Clojure(可能使用specter)中有一种简单的方法来过滤集合,具体取决于具有已知名称的任意嵌套关键字是否包含元素?clojure找到任意嵌套的键

Ex。 :

(def coll [{:res [{:a [{:thekey [ 
          "the value I am looking for" 
         ... 
        ] 
      } 
      ]} 
     {:res ...} 
     {:res ...} 
     ]}]) 

明知:a可以有不同的名称,并:thekey可能在其他地方嵌套。 假设我想做:

#(find-nested :thekey #{"the value I am looking for"} coll) ;; returns a vector containing the first element in coll (and maybe others) 
+0

必须收集矢量和地图吗?或者是否允许其他类型? –

+0

您能否澄清/提供您想要的返回值样本? – jmargolisvt

+0

@Elogent我只有向量,原始值和映射(即没有集合,这些值来自mongodb + congomongo数据库)。 – nha

回答

3

使用拉链。 在REPL:

user> coll 
[{:res [{:a [{:thekey ["the value I am looking for"]}]} {:res 1} {:res 1}]}] 

user> (require '[clojure.zip :as z]) 
nil 

user> (def cc (z/zipper coll? seq nil coll)) 
#'user/cc 

user> (loop [x cc] 
     (if (= (z/node x) :thekey) 
      (z/node (z/next x)) 
      (recur (z/next x)))) 
["the value I am looking for"] 

更新:

这个版本是有缺陷的,因为它并不关心:thekey是在地图的关键,或者只是一个载体关键字,因此它会给予coll [[:thekey [1 2 3]]]不需要的结果。下面是一个更新版本:

(defn lookup-key [k coll] 
    (let [coll-zip (z/zipper coll? #(if (map? %) (vals %) %) nil coll)] 
    (loop [x coll-zip] 
     (when-not (z/end? x) 
     (if-let [v (-> x z/node k)] v (recur (z/next x))))))) 

在REPL:

user> (lookup-key :thekey coll) 
["the value I am looking for"] 

user> (lookup-key :absent coll) 
nil 

,假设我们已经在科尔的地方相同的关键字在一个载体:

(def coll [{:res [:thekey 
        {:a [{:thekey ["the value I am looking for"]}]} 
        {:res 1} {:res 1}]}]) 
#'user/coll 

user> (lookup-key :thekey coll) 
["the value I am looking for"] 

这是我们所需要的。

+0

非常有用,从来没有玩过拉链,我会尝试看看处理嵌套的情况谢谢。 – nha

+1

忘记检查循环中的z/end,如果没有键,则会无限循环 – leetwinski