如何使用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)}