【问题标题】:How to merge list of maps in clojure如何在clojure中合并地图列表
【发布时间】:2018-04-30 14:48:39
【问题描述】:

我得到了一张地图列表:

({:a 1 :b ["red" "blue"]} {:a 2 :b ["green"]} {:a 1 :b ["yellow"]} {:a 2 :b ["orange"]})

我需要将它们组合起来最终看起来像这样:

({:a 1 :b ["red" "blue" "yellow"]} {:a 2 :b ["green" "orange"]})

根据键“a”的值组合地图的位置。 到目前为止,我有这个

(->> (sort-by :a)
     (partition-by :a)
     (map (partial apply merge)))

但是合并会用最后一个给我的向量覆盖“b”中的向量

({:a 1 :b ["yellow"]} {:a 2 :b ["orange"]}) 

【问题讨论】:

    标签: clojure


    【解决方案1】:

    merge-with代替merge,即

    (->> a (sort-by :a) 
           (partition-by :a) 
           (map (partial 
              apply 
              merge-with (fn [x y] (if (= x y) x (into x y))))))
    

    输出

    ({:a 1, :b ["red" "blue" "yellow"]} {:a 2, :b ["green" "orange"]})
    

    【讨论】:

      【解决方案2】:

      你真的不想对任何东西进行排序或分区:这只是 CPU 时间花在什么事情上,最后你有一个尴尬的数据结构(地图列表)而不是更方便的东西,a由“重要”:a 值键控的映射。

      相反,我会将其写为 reduce,其中每个步骤在最终映射的相应小节上使用 merge-with

      (defn combine-by [k ms]
        (reduce (fn [acc m]
                  (update acc (get m k) 
                          (partial merge-with into) 
                          (dissoc m k)))
                {}, ms))
      

      之后我们有

      user=> (combine-by :a '({:a 1 :b ["red" "blue"]} 
                              {:a 2 :b ["green"]} 
                              {:a 1 :b ["yellow"]} 
                              {:a 2 :b ["orange"]}))
      {1 {:b ["red" "blue" "yellow"]}, 2 {:b ["green" "orange"]}}
      

      这对于通过特定的:a 轻松查找地图很有用,或者如果您希望将结果作为列表返回,您可以轻松展开它。

      【讨论】:

        猜你喜欢
        • 2020-05-27
        • 1970-01-01
        • 2018-05-09
        • 1970-01-01
        • 2023-03-16
        • 1970-01-01
        • 1970-01-01
        • 2019-05-02
        相关资源
        最近更新 更多