2

我第一次尝试

(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])}

我刚刚发现我可以用向量包装地图的 vals:

(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)
4

3 回答 3

0

你可以试试这个:

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

;; {:a ([3 4] [1 2] [2 3])}

它可以工作,但依赖于输出集合的类型——在这种情况下是列表。这是我想出的最短的。

希望这可以帮助。

于 2013-04-07T04:30:00.880 回答
0

版本 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])}
于 2013-04-07T04:53:40.027 回答
0

以下解决方案还确保列表中项目的顺序基于地图的顺序。

(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)}
于 2013-04-07T08:13:51.070 回答