合并两个映射列表,其中条目在Clojure中由id标识

时间:2013-08-21 15:21:06

标签: clojure

在Clojure中合并两个地图列表的惯用方法是什么?每个地图条目都由一个id键标识?

foo的实施是什么,以便

(foo '({:id 1 :bar true :value 1} 
       {:id 2 :bar false :value 2} 
       {:id 3 :value 3})
     '({:id 5 :value 5} 
       {:id 2 :value 2} 
       {:id 3 :value 3}
       {:id 1 :value 1} 
       {:id 4 :value 4})) => '({:id 1 :bar true :value 1}
                               {:id 2 :bar false :value 2}
                               {:id 3 :value 3}
                               {:id 4 :value 4}
                               {:id 5 :value 5})

是真的吗?

3 个答案:

答案 0 :(得分:1)

这是通用的,因此您可以拥有任意数量的输入序列和任意分组选择器:

(def a [{:id 5 :value 5} 
        {:id 2 :value 2} 
        {:id 3 :value 3}
        {:id 1 :value 1} 
        {:id 4 :value 4}])

(def b [{:id 1 :bar true :value 1} 
        {:id 2 :bar false :value 2} 
        {:id 3 :value 3}])

(def c [{:id 1 :bar true :value 1}
        {:id 2 :bar false :value 2}
        {:id 3 :value 3}
        {:id 4 :value 4}
        {:id 5 :value 5}])

(defn merge-vectors
  [selector & sequences]
  (let [unpack-grouped (fn [group]
                         (into {} (map (fn [[k [v & _]]] [k v]) group)))
        grouped (map (comp unpack-grouped (partial group-by selector))
                     sequences)
        merged (apply merge-with merge grouped)]
    (sort-by selector (vals merged))))

(defn tst
  []
  (= c
   (merge-vectors :id a b)))

答案 1 :(得分:1)

这个怎么样:

(defn foo [& colls]
  (map (fn [[_ equivalent-maps]] (apply merge equivalent-maps)) 
       (group-by :id (sort-by :id (apply concat colls)))))

答案 2 :(得分:1)

(defn merge-by
  "Merges elems in seqs by joining them on return value of key-fn k.
   Example: (merge-by :id [{:id 0 :name \"George\"}{:id 1 :name \"Bernie\"}]
                          [{:id 2 :name \"Lara\"}{:id 0 :name \"Ben\"}])
   => [{:id 0 :name \"Ben\"}{:id 1 :name \"Bernie\"}{:id 2 :name \"Lara\"}]"
  [k & seqs]
  (->> seqs
       (map (partial group-by k))
       (apply merge-with (comp vector
                               (partial apply merge)
                               concat))
       vals
       (map first)))