2014-07-01 35 views
1

我試圖從輸入map創建一種還原索引。輸入地圖我得到的是:Clojure:使用切換鍵和其他地圖中的值創建地圖

{"id-1" {"values" ["a" "b" "c"]}, "id-2" {"values" ["a" "b" "c"]}} 

然後我想有這等映射作爲結果:

{"a" ["id-1" "id-2"], "b" ["id-1" "id-2"], "c" ["id-1" "id-2"]} 

但是,我認爲,我的腦海裏沒有發瘋,我覺得我畫自己變成角落裏沒有能夠思考的框框。下面是我得到了什麼,到目前爲止,它看起來像它太臭:

(->> {"id-1" {"values" ["a" "b" "c"]} "id-2" {"values" ["a" "b" "c"]}} 
     (map #(->> (get (second %) "values") 
       (map (fn [x y] (hash-map y x)) (into [] (repeat (count (get (second %) "values")) (first %)))) 
       (apply merge-with concat))) 
     (apply merge-with concat)) 

基本上,我仍然使用在「迭代」在我所有的輸入值第一map。然後,我使用第二個圖來創建一系列單獨的地圖看起來像:

({"a" "id-2"} {"b" "id-2"} {"c" "id-2"} {"a" "id-1"} {"b" "id-1"} {"c" "id-1"}) 

爲了達到這樣的地圖,我創建使用into [] (repeat ..)與價值觀的陣列一起喂到地圖中間陣列。

然後我將它們合併在一起以獲得我的期望值。

兩個問題在這裏:

  1. 這似乎真的要複雜得多,比我的直覺,這是
  2. ,因爲我得到這個當前的最終結果尚不完善:

    {「a」(\ i \ d - \ 1 \ i \ d - \ 2),「b」(\ i \ d - \ 1 \ i \ d - \ 2) \ 1 \ i \ d - \ 2)}

回答

2

鑑於此inpu T:

(def input {"id-1" {"values" ["a" "b" "c"]}, "id-2" {"values" ["a" "b" "c"]}}) 

很容易做到:

(defn extract [key values] 
    (for [v (get values "values")] {v [key]})) 

(->> input 
    (mapcat (partial apply extract)) 
    (apply merge-with concat)) 

,或者沒有附加功能:

(->> (for [[k vs] input] 
     (for [v (get vs "values")] {v [k]})) 
    (flatten) 
    (apply merge-with concat)) 

其中運作的,你希望的方式。

訣竅是將key換成extract函數的向量,所以merge-with concat不需要串聯字符串。

+0

感謝,它的工作原理完全如預期,並且肯定是很多很多打掃得比我做了什麼。然而,我不清楚在這種情況下「partial」是如何工作的,你能否詳細說明它在那裏的工作原理? – Neoasimov

+0

@Neoasimov它基本上創建了一個函數,它接受一個參數(或更多),然後使用該參數調用'apply extract'。比'#(apply extract%)'更好,恕我直言。 – sloth

+0

好的,謝謝你的解釋。是的,我注意到了這個變體,我正在分析它。這個例子非常適合在Clojure中尋找處理這類數據的新方法,謝謝!我得到了我需要的一切,甚至更多:) – Neoasimov

8

使用map destructuring

(apply merge-with into (for [[k {vs "values"}] input, v vs] {v [k]})) 

更清晰

(apply merge-with into 
    (for [[k m] input 
     v (get m "values")] 
    {v [k]})) 
+0

@ a-webb這真的很棒!但我不確定我是否完全瞭解它。你能解釋一下'[[k'vs'values'}] input,v vs''會發生什麼,我認爲這是我第一次看到這種解構語法。我的理解是'k'綁定到鍵'id-x',然後'vs'被綁定到vector或values(不知道'{}'如何影響解構)。但是,',v vs'這是爲了解構你剛剛解構的結構,以便'v'受到之前解構的價值的限制嗎?如果是這樣,是否有一些關於這種解構語法的文檔? – Neoasimov

+0

@Neoasimov此語法'(let [{a-value:a} my-map])'是[map destructuring](http://clojure.org/special_forms#Special%20Forms--Binding%20Forms%20 %28Destructuring%29-Map%20binding%20destructuring),將map中':a'鍵的值綁定到'a-value'。 ',vvs'是'for'的延續,如在[(for [row [[1 2 3] [4 5 6]]中]元素row]元素; =>(1 2 3 4 5 6)'。逗號只是空格,更典型的是你會看到換行符和縮進。 –

+1

@ A.Webb我喜歡這個答案比接受的答案好得多。作爲一種風格,我喜歡'(對於[[k m]輸入,v(得到m「值」)] ...)'稍微好一些,這只是因爲使用顯式地圖解構風格有點不尋常。 – amalloy