在Clojure中合并数组

时间:2012-06-25 21:15:05

标签: clojure

我需要基于id合并一组数组。

示例数据:

编辑:(更改为匹配Clojure数据结构)

 [{:id 1, :region :NA, :name :Test1, :OS :W}
  {:id 1, :region :EU, :name :Test2, :OS :W}
  {:id 2, :region :AS, :name :test3, :OS :L}
  {:id 2, :region :AS, :name :test4, :OS :M}]

变为:

编辑:(更改为匹配Clojure数据结构)

[{:id 1, :region [:NA :EU], :name [:Test1 :Test2] ,:OS [:W]}
 {:id 2, :region [:AS] :name [:test3 :Test4], :OS [:L :M]}]

|是分隔符(可更改) 如果可能的话,也希望按字母顺序排列。

3 个答案:

答案 0 :(得分:0)

您可以使用clojure.set中的某些功能组合(如果您将最外面的矢量更改为设置)。特别是clojure.set/index看起来很有希望。

答案 1 :(得分:0)

(def data
 [{:id 1, :region :NA, :name :Test1, :OS :W}
  {:id 1, :region :EU, :name :Test2, :OS :W}
  {:id 2, :region :AS, :name :test3, :OS :L}
  {:id 2, :region :AS, :name :test4, :OS :M}])

(defn key-join
  "join of map by key , value is distinct."
  [map-list]
  (let [keys (keys (first map-list))]
       (into {} (for [k keys] [k (vec (set (map #(% k) map-list)))]))))

(defn group-reduce [key map-list]
  (let [gdata (group-by key map-list)]
    (into [] (for [[k m] gdata] (let [m (key-join m)](assoc m key ((key m) 0)))))))



user=> (group-reduce :id data)
[{:name [:Test2 :Test1], :OS [:W], :region [:EU :NA], :id 1} {:name [:test3 :test4], :OS [:L :M], :region [:AS], :id 2}]

答案 2 :(得分:0)

您可以使用merge-with功能,如下例所示。

首先,我们定义了一些辅助函数

(defn collect [& xs]
  (apply vector (-> xs distinct sort)))

collect函数确保xs中的项目是唯一的并进行排序,最后将它们返回到向量中。

(defn merge-keys [k xs]
  (map #(apply merge-with collect %) (vals (group-by k xs))))

merge-keys首先将xs中的哈希映射分组为主键(在您的情况下为:id),获取每个分组项列表并使用以下内容合并键的值collect从上面开始运作。

(def xs [{:id 1, :region :NA, :name :Test1, :OS :W}
         {:id 1, :region :EU, :name :Test2, :OS :W}
         {:id 2, :region :AS, :name :test3, :OS :L}
         {:id 2, :region :AS, :name :test4, :OS :M}])

(merge-keys :id xs)
=> ({:id [1],
     :region [:EU :NA],
     :name [:Test1 :Test2],
     :OS [:W]}
    {:id [2],
     :region [:AS],
     :name [:test3 :test4],
     :OS [:L :M]})

注意但即使:id键现在也有与之关联的向量。您可以通过在if中引入collect语句轻松取消向量它,该语句将单个值与键而不是向量相关联...

(defn collect [& xs]
  (let [cs (apply vector (-> xs distinct sort))]
    (if (= 1 (count cs)) (first cs) cs)))

...或从merge-keys获取结果并执行

(map #(update-in % [:id] first) result)

只会取消向量 :id地图条目