2016-02-25 53 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