2012-06-27 98 views
1

我有一系列地图。将地图序列转换为多地图

;; input 
[{:country "MX", :video 12345, :customer "cid1"} 
{:country "US", :video 12345, :customer "cid2"} 
{:country "MX", :video 54321, :customer "cid1"}] 

我想将它转换成一个multimap。我想生成。

;; output 
{"cid1" 
    {:actions 
      [{:country "MX", :video 12345, :customer "cid1"} 
      {:country "MX", :video 12345, :customer "cid1"}]}, 
"cid2" 
    {:actions 
      [{:country "US", :video 12345, :customer "cid2"}]}} 

我觉得我应该使用update-in。有些事情......我只是没有弄清楚some-fn-here的样子,我想其他人可能会有同样的问题。

(defn add-mm-entry 
    [m e] 
    (update-in m [(:customer e)] some-fn-here)) 

(def output (reduce add-mm-entry {} input)) 

想象一下,当我工作时,我会把它扔给社区。如果我在这里走错了路,让我知道。

回答

5

如果我正确理解了意图,则按以下方式进行分组:客户,然后将行为向量包装到:actions中。您可以通过组做分组与clojure.core /然后映射(clojure.core /图)结果:

(def v [{:country "MX", :video 12345, :customer "cid1"} 
     {:country "US", :video 12345, :customer "cid2"} 
     {:country "MX", :video 54321, :customer "cid1"}]) 

(->> v 
    (group-by :customer) 
    (map (fn [[cid xs]] {cid {:actions xs}})) 
    (into {})) 
+1

最终输出应该是一张地图,所以你需要通过'(到{})'运行结果。 –

2

迈克尔的回答运作良好。我不确定group-by是否适合我的具体情况,因为我正在加载的数据的大小。我没有测试过,但我认为这种方法会导致中间产品减少。

(def v [{:country "MX", :video 12345, :customer "cid1"} 
     {:country "US", :video 12345, :customer "cid2"} 
     {:country "MX", :video 54321, :customer "cid1"}]) 

(defn add-entry 
    [m e] 
    (let [cust (:customer e)] 
     (update-in m [cust :actions] #(conj % e)))) 

(reduce add-entry {} v) 

仍导致完整的数据集被加载,但它被直接加载到目标数据结构,而不是插入的地图的矢量,然后进入一个多重映射。再一次,我没有测试过哪一个是明确更高性能的,但是看起来这个数据集的迭代次数少了一次,并且避免了创建来自group-by的不需要的映射向量。