如何使用Clojure的for将多个Map合并为单个Map?
问题描述
现有代码可基本运行,但输出数据格式不符合预期:
当前输出:
({"apples" {price 2}} {"pears" {price 4}})
期望输出(合并为单个Map):
{"apples" {price 2} "pears" {price 4}}
使用的代码:
(defn summarize-many-maps-with-keyname [ms] (for [m ms] {(first (keys m)) (summarize-one (first (vals m)))}))
问题:能否让for将结果合并为单个Map?若不能,有什么其他解决方案?
解决方案
首先明确:for表达式本身只会返回一个序列,无法直接生成单个Map,它每次迭代都会生成一个独立的小Map,最终输出的是这些小Map组成的序列,也就是你当前看到的结果。
要得到单个合并后的Map,有以下几种常用方案:
方案1:用into合并序列中的Map
把for生成的序列传入into,初始值设为空Map,into会自动将序列里的所有小Map合并成一个大Map:
(defn summarize-many-maps-with-keyname [ms] (into {} (for [m ms] {(first (keys m)) (summarize-one (first (vals m)))})))
方案2:改用reduce直接构建Map
reduce更适合逐步构建单个集合的场景,直接遍历输入的ms,每次把新的键值对合并到结果Map中:
(defn summarize-many-maps-with-keyname [ms] (reduce (fn [result m] (assoc result (first (keys m)) (summarize-one (first (vals m))))) {} ms))
方案3:mapcat+seq拆解后转Map
先把每个小Map转成键值对序列(比如({"a" 1})变为(["a" 1])),再用mapcat拼接成一个大的键值对序列,最后转成Map:
(defn summarize-many-maps-with-keyname [ms] (into {} (mapcat seq (for [m ms] {(first (keys m)) (summarize-one (first (vals m)))}))))
简化优化(针对输入特性)
如果你的输入ms中每个m本身就是仅含一个键值对的Map,还可以利用Clojure解构简化代码:
(defn summarize-many-maps-with-keyname [ms] (into {} (for [[k v] ms] [k (summarize-one v)])))
这里直接将单个键值对的Map解构成k和v,省去了(first (keys m))和(first (vals m))的冗余写法。
内容的提问来源于stack exchange,提问作者triplej
相关产品推荐
相关产品推荐

