2015-09-29 52 views
2

的所有的鍵:遍歷鑑於嵌套地圖

{:o {:i1 1 
    :i2 {:ii1 4}}} 

我想迭代中從根作爲載體「絕對」形式的地圖的鍵。所以我想:

{ 
[:o :i1] 1 
[:o :i2 :ii1] 4 
} 

因此。基本上只獲得葉節點。

+0

原來,它基本上是一個平坦的鍵:http://stackoverflow.com/questions/17901933/flattening-a-map-by-join-the-keys – ClojureMostly

+0

重複?還是應該回答? – ClojureMostly

回答

3

,我認爲一個版本是相當漂亮,使用for代替mapcat

(defn flatten-keys [m] 
    (if (not (map? m)) 
    {[] m} 
    (into {} 
      (for [[k v] m 
       [ks v'] (flatten-keys v)] 
      [(cons k ks) v'])))) 

功能自然是遞歸的,而對於非地圖最方便的基本情況是「這一個值,沒有keyseq導致它「。對於地圖,您可以在地圖上的每個值上調用flatten-keys,並將其密鑰添加到結果地圖的每個keyseq中。

+0

值得注意的是,因爲它只是咬我一口:如果你在地圖中保存記錄,這將會遍歷這些記錄(並且把所有的東西搞亂),因爲'(map?m)'對於記錄是真的。我改變了我的實現,以保持記錄。 – ClojureMostly

2

看起來這基本上是嵌套鍵的扁平化。這也似乎是a 4clojure problem

A flatten-map search on github產生許多結果。

一個示例實現:

(defn flatten-map 
    "Flattens the keys of a nested into a map of depth one but 
    with the keys turned into vectors (the paths into the original 
    nested map)." 
    [s] 
    (let [combine-map (fn [k s] (for [[x y] s] {[k x] y}))] 
    (loop [result {}, coll s] 
     (if (empty? coll) 
     result 
     (let [[i j] (first coll)] 
      (recur (into result (combine-map i j)) (rest coll))))))) 

(flatten-map {:OUT 
       {:x 5 
       :x/A 21 
       :x/B 33 
       :y/A 24}}) 
=> {[:OUT :x] 5, [:OUT :x/A] 21, [:OUT :x/B] 33, [:OUT :y/A] 24} 

一個甚至從克里斯托弗大更一般的版本:

(defn flatten-map 
    "Take a nested map (or a nested collection of key-value pairs) and returns a 
    sequence of key-value pairs where keys are replaced by the result of calling 
    (reduce f pk path) where path is the path to this key through the nested 
    maps." 
    ([f kvs] (flatten-map f nil kvs)) 
    ([f pk kvs] 
    (mapcat (fn [[k v]] 
      (if (map? v) 
       (flatten-map f (f pk k) v) 
       [[(f pk k) v]])) kvs))) 

實施例:

(flatten-map conj [] {:OUT 
       {:x 5 
       :x/A 21 
       :x/B 33 
       :y/A 24}}) 
=> ([[:OUT :x] 5] [[:OUT :x/A] 21] [[:OUT :x/B] 33] [[:OUT :y/A] 24])