将键值对添加到来自clojure中另一个地图列表的地图列表中的地图

时间:2016-07-20 07:41:06

标签: clojure clojure-java-interop clojure-contrib

我有一张地图列表

 ( {:path "first" :size "1 gb"}  
   {:path "second" :size "500 mb"}
  ...)

和另一个地图列表

 ( {:path "first" :size "1 gb" :date "1"}
   {:path "second" :size "500 mb" :date "1"}
   {:path "first" :size "0.9 gb" :date "2"}...
   {:path "second" :size "400 mb" :date "2"}...
 ...)

我希望将第一个地图列表转换为类似

的地图
( {:path "first" :sizeon1 "1 gb" :sizeon2 "0.9 gb"...}
  {:path "second" :sizeon1 "500 mb" :sizeon2 "400 mb"...}
  ....)

我是一个Clojure菜鸟,并且很难做到这一点。 你能帮帮我吗?

3 个答案:

答案 0 :(得分:2)

当你将任务分解成更小的部分时,一切都变得清晰。

首先,定义一个帮助程序,在结果数据集中创建:sizeon1个键:

(defn date-key
  [date]
  (keyword (str "sizeon" date)))

接下来,您希望将单个路径数据的集合减少为聚合映射,假设这样的集合看起来如您所述:

[{:path "first" :size "1 gb" :date "1"}
 {:path "first" :size "0.9 gb" :date "2"}
 ;; ...
 ]

reduce只是其中的工具:

(defn reduce-path
  [path-data]
  (reduce
    ;; A function that takes an accumulator map and an element in the collection
    ;; from which you take date and size and assoc them under the appropriate keys
    (fn [acc el]
      (let [{:keys [date size]} el]
        (assoc acc (date-key date) size)))
    ;; A starting value for the accumulator containing the common path
    ;; for this collection
    {:path (:path (first path-data))}
    ;; The collection of single path data to reduce
    path-data))

最后,获取包含不同路径的原始数据集,按路径对其进行分区,并将reduce-path函数映射到其上。

(def data
  [{:path "first" :size "1 gb" :date "1"}
   {:path "first" :size "0.9 gb" :date "2"}
   {:path "second" :size "500 mb" :date "1"}
   {:path "second" :size "400 mb" :date "2"}])

(->> data
     (partition-by :path)
     (map reduce-path))

请注意,此代码假定您的初始data集合已按:path排序。否则,partition-by将无法正常工作,并且必须相应地准备数据。

答案 1 :(得分:2)

(def data '({:path "first" :size "1 gb" :date "1"}
            {:path "second" :size "500 mb" :date "1"}
            {:path "first" :size "0.9 gb" :date "2"}
            {:path "second" :size "400 mb" :date "2"}))

(defn- reduce-group [g]
  (reduce (fn [acc m] (assoc acc
                             (keyword (str "sizeon" (:date m)))
                             (:size m)))
          (first g) g))

(let [groups (group-by :path data)]
  (map reduce-group (vals groups)))

答案 2 :(得分:2)

我该怎么做,是重新考虑结果数据结构: 我不知道您将如何使用生成的集合,但命名密钥:sizeonX,尤其是当可能存在可变数量的注册日期或者可能缺少其中一些时(例如,如果您有日期{第一条路径为{1}}和1,第二条路径为3 1 2 3,导致一系列不可预测的命名密钥地图,这将使得检索这些密钥变得更加困难。 对我而言,使用这种结构似乎更好:

5

所以这个尺寸图很容易迭代和处理。

我将如何做到这一点:

{:path "first" :sizes {"1" "500" "2" "1g" "10" "222"}}

<强>更新

但是你仍然需要问题的结构,我会这样做:

(def data '({:path "first" :size "1 gb" :date "1"}
            {:path "first" :size "0.9 gb" :date "3"}
            {:path "second" :size "500 mb" :date "1"}
            {:path "second" :size "700 mb" :date "2"}
            {:path "second" :size "400 mb" :date "3"}
            {:path "second" :size "900 mb" :date "5"}))

(map (fn [[k v]] {:path k
                  :sizes (into {} (map (juxt :date :size) v))})
     (group-by :path data))

;; ({:path "first", :sizes {"1" "1 gb", "3" "0.9 gb"}} 
;;  {:path "second", :sizes {"1" "500 mb", 
;;                           "2" "700 mb", 
;;                           "3" "400 mb", 
;;                           "5" "900 mb"}})

基本上类似于@superkonduktr变种。