如何在Clojure中按指定Key合并Map列表
Clojure按指定键分组合并Map列表的正确实现方法
你遇到的问题很典型——merge确实会对相同键的值做覆盖,而不是合并集合,所以才会只保留每个分组里最后一个Map的:b向量。这里给你两种靠谱的实现方式,都能达到你要的分组合并效果:
方法一:用group-by配合分组处理
这是最直观的思路,先按:a分组,再把每个分组里的:b向量合并起来:
(def data '({:a 1 :b ["red" "blue"]} {:a 2 :b ["green"]} {:a 1 :b ["yellow"]} {:a 2 :b ["orange"]})) (->> data (group-by :a) ; 第一步:按:a的值分组,得到 {1 [{:a 1 ...}, {:a 1 ...}], 2 [...]} (map (fn [[group-key maps-in-group]] {:a group-key :b (mapcat :b maps-in-group)}))) ; 把分组里所有:b的向量拼接成一个
运行这段代码后,就能得到你想要的结果:({:a 1 :b ("red" "blue" "yellow")} {:a 2 :b ("green" "orange")})
如果需要向量而不是序列的话,把:b那行改成(vec (mapcat :b maps-in-group))就行。
方法二:用reduce逐步合并
如果你更喜欢用reduce来做累积式的处理,也可以这样写:
(def merged-data (->> data (reduce (fn [acc current-map] ; 先取出当前分组已有的数据,没有的话初始化一个空的:b向量 (let [existing-group (get acc (:a current-map) {:a (:a current-map) :b []})] ; 更新分组里的:b向量,把当前Map的:b加进去 (assoc acc (:a current-map) (update existing-group :b into (:b current-map))))) {}) ; 最后把累积的Map的values取出来,就是最终的列表 vals))
这个方法的好处是不需要先排序或分组,直接遍历一次数据就完成合并,效率也不错。
两种方法都能解决你的问题,选你觉得更顺手的就行~
内容的提问来源于stack exchange,提问作者HavocShot
相关产品推荐
相关产品推荐

