如何使用merge with在clojure中创建重复键列表

如何使用merge with在clojure中创建重复键列表,clojure,Clojure,我第一次试过 (merge-with list maps) 它适用于具有单一值的地图, 但是对于像这样的事情 {:a [1 2]} {:a [2 3]} {:a [3 4]} 它给了我 {:a (([1 2] [2 3]) [3 4])} 但是我想要 {:a ([1 2] [2 3] [3 4])} 我刚刚发现我可以用向量包装地图的VAL: (defn my-merge [& coll] (let [maps (map #(assoc % (first (keys %))

我第一次试过

(merge-with list maps)
它适用于具有单一值的地图, 但是对于像这样的事情

{:a [1 2]} {:a [2 3]} {:a [3 4]}
它给了我

{:a (([1 2] [2 3]) [3 4])}
但是我想要

{:a ([1 2] [2 3] [3 4])}
我刚刚发现我可以用向量包装地图的VAL:

(defn my-merge
  [& coll]
  (let [maps (map #(assoc % (first (keys %)) [(first (vals %))]) coll)]
    (apply merge-with concat maps)))
但是let绑定似乎太嵌套了,有没有更简单的函数可以替代concat?所以我可以有一些单行代码,比如:

(merge-with the-function maps)
您可以尝试以下方法:

(merge-with (fn [a b] 
  (if (list? a) 
      (conj a b) 
      (list a b))) 
  maps)

;; {:a ([3 4] [1 2] [2 3])}
它可以工作,但在本例中依赖于输出集合列表的类型。这是我想出的最短的

希望这能有所帮助。

第1版

(defn my-merge [f & mlist] 
  (into {} 
        (map (fn [[k v]] [k (apply f (map val v))]) 
             (group-by key (apply concat mlist)))))

(my-merge list
          {:a [1 2]} 
          {:a [2 3] :b :two} 
          {:a [3 4] :b :one})

=> {:a ([1 2] [2 3] [3 4]) :b (:two :one)}
版本2

(defn my-merge [f initv & mlist] 
  (apply merge-with f 
         (apply merge-with (fn [_ _] initv) mlist)
         mlist))

(my-merge conj ()
          {:a [1 2]} 
          {:a [2 3] :b :two} 
          {:a [3 4] :b :one})

=> {:b (:one :two), :a ([3 4] [2 3] [1 2])}

下面的解决方案还确保列表中项目的顺序基于映射的顺序

(def maps [{:a [1 2]} 
          {:a [2 3] :b :two} 
          {:a [3 4] :b :one}])

(into {} (for [k (into #{} (mapcat keys maps))
               :let [obj (Object.)]]
           [k (filter (partial not= obj)
                      (map #(get % k obj) maps))]))

=> {:a ([1 2] [2 3] [3 4]), :b (:two :one)}