Clojure:遍历映射向量并添加重复的元素
Clojure: traversing map vectors and adding elements that repeat
希望你们一切都好。好吧,我是 Clojure 编程的新手,需要一些帮助。我有以下地图矢量:
(def curves [{:curve_buyer "curve1" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 4}
{:curve_buyer "curve3" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve2" :quantity 4 :value 4}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 4}])
我需要对该向量进行检查,它检查具有相同值的键(:curve_buyer 和 :curve_seller)。如果它们具有相同的值,我需要添加数量和值,否则 return 地图原样。拿上面的地图我会有以下 return.
(def curves [{:curve_buyer "curve1" :curve_seller "curve2" :quantity 6 :value 7}
{:curve_buyer "curve2" :curve_seller "curve3" :quantity 2 :value 4}
{:curve_buyer "curve3" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curva3" :quantity 4 :value 7}])
我需要一个函数来执行此操作。任何使用 clojure 函数的方法或可以解决我问题的函数的想法。
感谢您的关注,我愿意进行任何澄清。
您的输出可能是错误的,因为地图 {:curve_buyer "curve2" :curve_seller "curve3" :quantity 2 :value 4}
不在 curves
.
中
这个任务可以用 group-by
and merge-with
来解决。首先,按给定键将地图分组:
(def curves [{:curve_buyer "curve1" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 4}
{:curve_buyer "curve3" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve2" :quantity 4 :value 4}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 4}])
(->> curves
(group-by (juxt :curve_buyer :curve_seller)))
=>
{["curve1" "curve2"] [{:curve_buyer "curve1", :curve_seller "curve2", :quantity 2, :value 3}
{:curve_buyer "curve1", :curve_seller "curve2", :quantity 4, :value 4}],
["curve1" "curve3"] [{:curve_buyer "curve1", :curve_seller "curve3", :quantity 2, :value 4}
{:curve_buyer "curve1", :curve_seller "curve3", :quantity 2, :value 3}
{:curve_buyer "curve1", :curve_seller "curve3", :quantity 2, :value 4}],
["curve3" "curve2"] [{:curve_buyer "curve3", :curve_seller "curve2", :quantity 2, :value 3}]}
然后使用merge-with
将每组中的地图合并为一个:
(->> curves
(group-by (juxt :curve_buyer :curve_seller))
(map (fn [[k v]] (apply merge-with
(fn [o1 o2] (if (number? o1) (+ o1 o2) o1))
v))))
=>
({:curve_buyer "curve1", :curve_seller "curve2", :quantity 6, :value 7}
{:curve_buyer "curve1", :curve_seller "curve3", :quantity 6, :value 11}
{:curve_buyer "curve3", :curve_seller "curve2", :quantity 2, :value 3})
作为函数:
(defn summarize-by-keys [keys summary-fn list-of-maps]
(->> list-of-maps
(group-by (apply juxt keys))
(map (fn [[k v]] (apply merge-with
summary-fn
v)))))
;; call it by:
(summarize-by-keys [:curve_buyer :curve_seller]
#(if (number? %1) (+ %1 %2) %1)
curves)
您可以使用reduce
遍历curves
的每个元素,一次创建或更新结果的相应元素。
(reduce (fn [res m]
(let [{:keys [curve_buyer curve_seller quantity value]} m
;; idx is the index of the current buyer/seller
;; in the partial result or nil
idx (first (keep-indexed (fn [i x]
(when (and (= (:curve_buyer x) curve_buyer)
(= (:curve_seller x) curve_seller))
i))
res))]
(if idx
(update res
idx
#(assoc %
:quantity (+ quantity (:quantity %))
:value (+ value (:value %))))
(conj res m))))
[]
curves
最后的结果是:
[{:curve_buyer "curve1",
:curve_seller "curve2",
:quantity 6,
:value 7}
{:curve_buyer "curve1",
:curve_seller "curve3",
:quantity 6,
:value 11}
{:curve_buyer "curve3",
:curve_seller "curve2",
:quantity 2,
:value 3}]
请注意,向量可以被视为关联集合,元素的索引是键。
(require '[net.cgrand.xforms :as x])
(->> curves
(group-by (juxt :curve_buyer :curve_seller))
(map last)
(map (fn [xs] (into (first xs)
(x/multiplex
{:quantity (comp (map :quantity) (x/reduce +))
:value (comp (map :value) (x/reduce +))}) xs))))
你也可以这样做:
首先想到的是把每一项都做成map的函数,包含index key和values来汇总:
(defn mappify [ks vs item]
{(select-keys item ks) (select-keys item vs)})
(mappify [:curve_buyer :curve_seller]
[:quantity :value]
(first curves))
;;=>{{:curve_buyer "curve1", :curve_seller "curve2"}
;; {:quantity 2, :value 3}}
然后你可以映射所有的项目,并合并它们:
(->> curves
(map #(mappify [:curve_buyer :curve_seller]
[:quantity :value] %))
(apply merge-with (partial merge-with +))
(map (partial apply into)))
;;({:curve_buyer "curve1",
;; :curve_seller "curve2",
;; :quantity 6,
;; :value 7}
;;{:curve_buyer "curve1",
;; :curve_seller "curve3",
;; :quantity 6,
;; :value 11}
;;{:curve_buyer "curve3",
;; :curve_seller "curve2",
;; :quantity 2,
;; :value 3})
使用 reduce 和 map。你可以先在reduce中做总结。 group-by看似简单,其实是用reduce进行分组,而不是汇总
(->> curves
(reduce (fn [m {:keys [buyer seller q v]}]
(update m [buyer seller]
#(-> %
(update :q (fnil + 0) q)
(update :v (fnil + 0) v))))
{})
(map (fn [[[buyer seller] m]]
(assoc m :buyer buyer :seller seller))))
你也可以使用地图作为键
(->> curves
(reduce (fn [m {:keys [q v] :as curve}]
(update m (select-keys curve [:buyer :seller])
#(-> %
(update :q (fnil + 0) q)
(update :v (fnil + 0) v))))
{})
(map (fn [[km sm]] (merge km sm))))
所以作为函数
(defn summary-list
[l key-keys val-keys]
(->> (reduce (fn [acc m]
(update acc (select-keys m key-keys)
#(reduce (fn [vm vk]
(update vm vk
(fnil + 0)
(get m vk)))
% val-keys)))
{} l)
(map (partial reduce merge))))
像这样打电话
(summary-list curves [:curve_buyer :curve_seller] [:quantity :value])
希望你们一切都好。好吧,我是 Clojure 编程的新手,需要一些帮助。我有以下地图矢量:
(def curves [{:curve_buyer "curve1" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 4}
{:curve_buyer "curve3" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve2" :quantity 4 :value 4}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 4}])
我需要对该向量进行检查,它检查具有相同值的键(:curve_buyer 和 :curve_seller)。如果它们具有相同的值,我需要添加数量和值,否则 return 地图原样。拿上面的地图我会有以下 return.
(def curves [{:curve_buyer "curve1" :curve_seller "curve2" :quantity 6 :value 7}
{:curve_buyer "curve2" :curve_seller "curve3" :quantity 2 :value 4}
{:curve_buyer "curve3" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curva3" :quantity 4 :value 7}])
我需要一个函数来执行此操作。任何使用 clojure 函数的方法或可以解决我问题的函数的想法。
感谢您的关注,我愿意进行任何澄清。
您的输出可能是错误的,因为地图 {:curve_buyer "curve2" :curve_seller "curve3" :quantity 2 :value 4}
不在 curves
.
这个任务可以用 group-by
and merge-with
来解决。首先,按给定键将地图分组:
(def curves [{:curve_buyer "curve1" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 4}
{:curve_buyer "curve3" :curve_seller "curve2" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 3}
{:curve_buyer "curve1" :curve_seller "curve2" :quantity 4 :value 4}
{:curve_buyer "curve1" :curve_seller "curve3" :quantity 2 :value 4}])
(->> curves
(group-by (juxt :curve_buyer :curve_seller)))
=>
{["curve1" "curve2"] [{:curve_buyer "curve1", :curve_seller "curve2", :quantity 2, :value 3}
{:curve_buyer "curve1", :curve_seller "curve2", :quantity 4, :value 4}],
["curve1" "curve3"] [{:curve_buyer "curve1", :curve_seller "curve3", :quantity 2, :value 4}
{:curve_buyer "curve1", :curve_seller "curve3", :quantity 2, :value 3}
{:curve_buyer "curve1", :curve_seller "curve3", :quantity 2, :value 4}],
["curve3" "curve2"] [{:curve_buyer "curve3", :curve_seller "curve2", :quantity 2, :value 3}]}
然后使用merge-with
将每组中的地图合并为一个:
(->> curves
(group-by (juxt :curve_buyer :curve_seller))
(map (fn [[k v]] (apply merge-with
(fn [o1 o2] (if (number? o1) (+ o1 o2) o1))
v))))
=>
({:curve_buyer "curve1", :curve_seller "curve2", :quantity 6, :value 7}
{:curve_buyer "curve1", :curve_seller "curve3", :quantity 6, :value 11}
{:curve_buyer "curve3", :curve_seller "curve2", :quantity 2, :value 3})
作为函数:
(defn summarize-by-keys [keys summary-fn list-of-maps]
(->> list-of-maps
(group-by (apply juxt keys))
(map (fn [[k v]] (apply merge-with
summary-fn
v)))))
;; call it by:
(summarize-by-keys [:curve_buyer :curve_seller]
#(if (number? %1) (+ %1 %2) %1)
curves)
您可以使用reduce
遍历curves
的每个元素,一次创建或更新结果的相应元素。
(reduce (fn [res m]
(let [{:keys [curve_buyer curve_seller quantity value]} m
;; idx is the index of the current buyer/seller
;; in the partial result or nil
idx (first (keep-indexed (fn [i x]
(when (and (= (:curve_buyer x) curve_buyer)
(= (:curve_seller x) curve_seller))
i))
res))]
(if idx
(update res
idx
#(assoc %
:quantity (+ quantity (:quantity %))
:value (+ value (:value %))))
(conj res m))))
[]
curves
最后的结果是:
[{:curve_buyer "curve1",
:curve_seller "curve2",
:quantity 6,
:value 7}
{:curve_buyer "curve1",
:curve_seller "curve3",
:quantity 6,
:value 11}
{:curve_buyer "curve3",
:curve_seller "curve2",
:quantity 2,
:value 3}]
请注意,向量可以被视为关联集合,元素的索引是键。
(require '[net.cgrand.xforms :as x])
(->> curves
(group-by (juxt :curve_buyer :curve_seller))
(map last)
(map (fn [xs] (into (first xs)
(x/multiplex
{:quantity (comp (map :quantity) (x/reduce +))
:value (comp (map :value) (x/reduce +))}) xs))))
你也可以这样做:
首先想到的是把每一项都做成map的函数,包含index key和values来汇总:
(defn mappify [ks vs item]
{(select-keys item ks) (select-keys item vs)})
(mappify [:curve_buyer :curve_seller]
[:quantity :value]
(first curves))
;;=>{{:curve_buyer "curve1", :curve_seller "curve2"}
;; {:quantity 2, :value 3}}
然后你可以映射所有的项目,并合并它们:
(->> curves
(map #(mappify [:curve_buyer :curve_seller]
[:quantity :value] %))
(apply merge-with (partial merge-with +))
(map (partial apply into)))
;;({:curve_buyer "curve1",
;; :curve_seller "curve2",
;; :quantity 6,
;; :value 7}
;;{:curve_buyer "curve1",
;; :curve_seller "curve3",
;; :quantity 6,
;; :value 11}
;;{:curve_buyer "curve3",
;; :curve_seller "curve2",
;; :quantity 2,
;; :value 3})
使用 reduce 和 map。你可以先在reduce中做总结。 group-by看似简单,其实是用reduce进行分组,而不是汇总
(->> curves
(reduce (fn [m {:keys [buyer seller q v]}]
(update m [buyer seller]
#(-> %
(update :q (fnil + 0) q)
(update :v (fnil + 0) v))))
{})
(map (fn [[[buyer seller] m]]
(assoc m :buyer buyer :seller seller))))
你也可以使用地图作为键
(->> curves
(reduce (fn [m {:keys [q v] :as curve}]
(update m (select-keys curve [:buyer :seller])
#(-> %
(update :q (fnil + 0) q)
(update :v (fnil + 0) v))))
{})
(map (fn [[km sm]] (merge km sm))))
所以作为函数
(defn summary-list
[l key-keys val-keys]
(->> (reduce (fn [acc m]
(update acc (select-keys m key-keys)
#(reduce (fn [vm vk]
(update vm vk
(fnil + 0)
(get m vk)))
% val-keys)))
{} l)
(map (partial reduce merge))))
像这样打电话
(summary-list curves [:curve_buyer :curve_seller] [:quantity :value])