我正在尝试使用clojure将多个地图合并到一个地图中。
输入
{:a 1 :b "a"}
{:a 2 :b "b"}
{:a 3 :b "c"}
{:a 4 :b "a"}
预期
{:a #{1,2,3,4}, :b #{"a" "b" "c"}}
每个键的值都会转换为原始地图中的一组值。
答案 0 :(得分:5)
我使用merge-with
,使用包含空集的预构建结构:
(def data [{:a 1 :b "a"}
{:a 2 :b "b"}
{:a 3 :b "c"}
{:a 4 :b "a"}])
(let [base {:a #{} :b #{}}]
(apply merge-with conj base data))
=> {:a #{1 2 3 4}, :b #{"a" "b" "c"}}
在基本映射中使用空集的技巧是conj
有一个具体的对象可以处理,因此可以正常工作。
答案 1 :(得分:4)
merge-with
可用于此:
(def d [{:a 1 :b "a"}
{:a 2 :b "b"}
{:a 3 :b "c"}
{:a 4 :b "a"}])
(def initial (into {} (map #(vector %1 []) (keys (apply merge d)))))
(into {} (map (fn [[a b]] [a (set b)])
(apply merge-with (fn [a b] (conj a b)) initial d)))
答案 2 :(得分:2)
(defn value-sets [& maps]
(reduce (fn [acc map]
(reduce (fn [m [k v]]
(update-in m [k] (fnil conj #{}) v))
acc
map))
{} maps))
编辑或者
(defn value-sets [& maps]
(reduce (fn [acc [k v]]
(update-in acc [k] (fnil conj #{}) v))
{}
(apply concat maps)))
多年后进一步编辑:我现在写的不同了:
(defn value-sets [maps]
(apply merge-with into (for [m maps, [k v] m]
{k #{v}})))
答案 3 :(得分:1)
看到涉及reduce
的amalloy解决方案向我提出了这个建议:
(def maps [{:a 1 :b 2}
{:a 11 :b 22 :c 5}
{:c 6 :a 7}])
(defn my-merge-maps
[maps]
(reduce (fn [accum [k v]]
(if (accum k)
(assoc accum k (conj (accum k) v))
(assoc accum k #{v})))
{}
(apply concat maps)))
(defn -main
[]
(println (my-merge-maps maps)))
结果是:{:c #{5 6}, :b #{2 22}, :a #{1 7 11}}
(感谢gfredericks指出我不小心使用了varargs。:))
编辑:以下是另一种方式,使用merge-with
:
(def maps [{:a 1 :b 2}
{:a 11 :b 22 :c 5}
{:c 6 :a 7}])
(defn build-up-set
[curr-val new-val]
(if (set? curr-val)
(conj curr-val new-val)
#{curr-val new-val}))
(defn my-merge-maps
[maps]
(apply merge-with build-up-set maps))
(defn -main
[]
(println (my-merge-maps maps)))
答案 4 :(得分:0)
这是一个流水线方法:
(defn my-merge-maps [stuff]
(->> stuff
(apply concat)
(group-by first)
(map (fn [[k vs]] [k (set (map second vs))]))
(into {})))
如果我们有正确的核心功能来操作它们,可以在地图中完成吗?
答案 5 :(得分:0)
(def data [{:a 1 :b "a"}
{:a 2 :b "b"}
{:a 3 :b "c"}
{:a 4 :b "a"}])
(apply
merge-with
clojure.set/union
(map #(zipmap (keys %) (map hash-set (vals %))) data))
;{:b #{"a" "b" "c"}, :a #{1 2 3 4}}
答案 6 :(得分:0)
Amalloy昨天就IRC上的同一问题放弃了以下解决方案:
(defn value-sets [& maps]
(apply merge-with into (for [m maps, [k v] m] {k #{v}})))