从clojure中的另一个映射列表向映射列表中的映射添加键值对
我有一张地图清单从clojure中的另一个映射列表向映射列表中的映射添加键值对,clojure,clojure-java-interop,clojure-contrib,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
( {: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" :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 noob,很难做到这一点。
你能帮帮我吗?当你把任务分解成更小的部分时,一切都变得清晰了 首先,定义一个帮助器以在结果数据集中创建那些
: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))
请注意,此代码假定初始
数据
集合已按:path
排序。否则,按划分的将无法像您预期的那样工作,并且必须相应地准备数据。当您将任务分解为更小的部分时,一切都变得清晰起来
(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)))
首先,定义一个帮助器以在结果数据集中创建那些: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))
请注意,此代码假定初始数据
集合已按:path
排序。否则,按
划分的将无法像您预期的那样工作,并且必须相应地准备数据。我要做的是重新考虑生成的数据结构:
(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)))
我不知道您可能会如何使用生成的集合,但命名键:sizeonX
,尤其是在注册日期数量可能可变或其中某些日期缺失的情况下(例如,如果第一条路径的日期为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"}})
更新
但由于您仍然需要问题的结构,我会这样做:
(map (fn [[k v]]
(into {:path k}
(map #(vector (keyword (str "sizeon" (:date %)))
(:size %))
v)))
(group-by :path data))
;;({:path "first", :sizeon1 "1 gb", :sizeon3 "0.9 gb"}
;; {:path "second",
;; :sizeon1 "500 mb", :sizeon2 "700 mb",
;; :sizeon3 "400 mb", :sizeon5 "900 mb"})
基本上与@superkonduktr variant相似。我要做的是重新考虑生成的数据结构:
我不知道您可能会如何使用生成的集合,但命名键:sizeonX
,尤其是在注册日期数量可能可变或其中某些日期缺失的情况下(例如,如果第一条路径的日期为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"}})
更新
但由于您仍然需要问题的结构,我会这样做:
(map (fn [[k v]]
(into {:path k}
(map #(vector (keyword (str "sizeon" (:date %)))
(:size %))
v)))
(group-by :path data))
;;({:path "first", :sizeon1 "1 gb", :sizeon3 "0.9 gb"}
;; {:path "second",
;; :sizeon1 "500 mb", :sizeon2 "700 mb",
;; :sizeon3 "400 mb", :sizeon5 "900 mb"})
这基本上与@superkonduktr variant相似。非常感谢!正如您所说,如果集合不按:path排序,则按分区将不起作用。我的数据是这样的:所有地图都先显示:date“1”,然后显示:date“2”,依此类推……您能告诉我在这种情况下该怎么办吗?在这种情况下,您应该替换(按:path分区)
行有两行:(group by:path)
和VAL
。这与group by
将项目分组到一个映射中具有相同的效果,其中的值是类似于分区结果的集合。
除了@leetwinski的建议之外,值得一提的是,您的数据缺少一个合理的(理想情况下是数字的)值要对其执行排序的字段。然后可以使用(排序依据:可排序键集合)
在将集合提供给缩减函数之前,请确保正确的顺序。有关一些用法示例,请参阅!我已使用排序方式为该函数创建了一个函数。非常感谢!正如您所说,如果集合未按:路径排序,则分区方式将不起作用。我的数据是这样的:所有地图首先显示:date“1”,然后显示:date“2”诸如此类……您能告诉我在这种情况下该怎么办吗?在这种情况下,您应该将(分区依据:路径)
行替换为两行:(分组依据:路径)
和VAL
。这与分组方式
将项目分组到地图中的效果相同,其中的值是类似于分区方式
结果的集合除了@leetwinski的建议之外,值得一提的是,您的数据缺少一个合理的(理想情况下是数字)字段来执行排序。然后您可以使用(sort by:sortable key collection)
以确保在将集合提供给Reduced函数之前的顺序正确。有关一些用法示例,请参阅!我使用sort by为该函数创建了一个函数。我猜这是错误的,因为op可能希望根据键的:date
值命名键(可能会有更多。(:size3
等)我猜这是错误的,因为op可能想根据键的:date
值命名键(可能会有更多。:size3
等)在您的示例中,您并不真正需要第一个列表,因为它的数据在第二个列表中重复。它总是正确的,还是存在某些路径值的情况