在clojure中,如何合并将映射与相同键组合在一起的多个映射到列表中?

vie*_*bel 19 clojure

在Clojure中,我想将几​​个映射组合成一个映射,其中具有相同键的映射被组合到一个列表中.

例如:

{:humor :happy} {:humor :sad} {:humor :happy} {:weather :sunny}
Run Code Online (Sandbox Code Playgroud)

应该导致:

{:weather :sunny, :humor (:happy :sad :happy)}
Run Code Online (Sandbox Code Playgroud)

我想过:

(merge-with (comp flatten list) data)
Run Code Online (Sandbox Code Playgroud)

但它效率不高,因为flatten具有O(n)复杂度.

然后我提出:

(defn agg[x y] (if (coll? x) (cons y x) (list y x)))
(merge-with agg data)
Run Code Online (Sandbox Code Playgroud)

但这感觉不是惯用的.还有其他想法吗?

ama*_*loy 12

一种方法是

(defn merge-lists [& maps]
  (reduce (fn [m1 m2]
            (reduce (fn [m [k v]]
                      (update-in m [k] (fnil conj []) v))
                    m1, m2))
          {}
          maps))
Run Code Online (Sandbox Code Playgroud)

这有点难看,但这只是因为你的价值不是列表.它还强制所有内容都成为一个列表(所以你得到的:weather [:sunny]不是:weather :sunny).坦率地说,无论如何,这对你来说可能要容易百万倍.

如果你已经将每个值都作为向量,那么你可以做到(apply merge-with into maps).