【问题标题】:Cummulative addition on a vector of maps in clojureclojure中地图向量的累积加法
【发布时间】:2021-07-07 15:51:12
【问题描述】:

我有一个看起来像这样的数据集

[{1 "a"} {2 "b"} {3 "c"}]

我想把它变成一个看起来像这样的累积地图

{1 "a" 3 "b" 6 "c"}

我认为我目前的方法是冗长的。到目前为止,我想出了

(reduce 
  (fn [sum item] 
      (assoc sum (+ (reduce + (keys sum)) 
                    (key (first item))) 
                 (val (first item)))) 
   split-map)

但是键上的加法不正确。有谁知道我可以如何改进这一点?

【问题讨论】:

  • 如果您的输入数据中有任何 0,您的问题就无法解决。您确定要输出为地图而不是成对序列吗?

标签: clojure


【解决方案1】:

还有一个更有趣的版本:

(->> data
     (reductions (fn [[sum] m] (update (first m) 0 + sum)) [0])
     rest
     (into {}))

;;=> {1 "a", 3 "b", 6 "c"}

诀窍是归约函数对先前和当前的键值对进行操作,更新当前对的键:

(reductions (fn [[sum] m] (update (first m) 0 + sum)) [0] data)
;;=> ([0] [1 "a"] [3 "b"] [6 "c"])

【讨论】:

    【解决方案2】:

    如果您喜欢换能器:

    (require '[net.cgrand.xforms :as xf])
    (let [data [{1 "a"} {2 "b"} {3 "c"}]]
        (into {} (comp
                     (map first)
                     (xf/multiplex [(map last)
                                    (comp (map first) (xf/reductions +) (drop 1))])
                     (partition-all 2)) data))
    => {1 "a", 3 "b", 6 "c"}
    

    【讨论】:

      【解决方案3】:

      这是一个可能的计算实现,它广泛使用了 Clojure 序列函数:

      (defn cumul-pairs [data]
        (zipmap (rest (reductions ((map (comp key first)) +) 0 data))
                (map (comp val first) data)))
      
      (cumul-pairs [{1 "a"} {2 "b"} {3 "c"}])
      ;; => {1 "a", 3 "b", 6 "c"}
      

      在此代码中,表达式 (rest (reductions ((map (comp first keys)) +) 0 data)) 计算结果映射的键,表达式 (map (comp first vals) data) 计算值。然后我们将它们与zipmap 结合起来。函数reductionsreduce 一样工作,但返回所有中间结果的序列,而不仅仅是最后一个。看起来很奇怪的子表达式((map (comp first keys)) +) 是归约函数,我们使用mapping 转换器从+ 归约函数构造一个归约函数,该函数将在添加之前映射输入值。

      【讨论】:

      • 感谢您的解释,这很有帮助。我选择这个作为接受的答案,因为它是一个简洁的单行。
      【解决方案4】:

      要简洁地解决这个问题有点尴尬。这是一种方法:

      (ns tst.demo.core
        (:use tupelo.core tupelo.test))
      
      (dotest
        (let-spy
          [x1       [{1 "a"} {2 "b"} {3 "c"}]
           nums     (mapv #(first (first %)) x1)
           chars    (mapv #(second (first %)) x1)
           nums-cum (reductions + nums)
           pairs    (mapv vector nums-cum chars)  ; these 2 lines are
           result   (into {} pairs)]              ;   like `zipmap`
          (is= result {1 "a", 3 "b", 6 "c"})))
      

      通过使用我的favorite template project 我们可以从the Tupelo library 使用let-spy 并查看每一步打印的结果:

      -----------------------------------
         Clojure 1.10.3    Java 15.0.2
      -----------------------------------
      
      Testing tst.demo.core
      x1       => [{1 "a"} {2 "b"} {3 "c"}]
      nums     => [1 2 3]
      chars    => ["a" "b" "c"]
      nums-cum => (1 3 6)
      pairs    => [[1 "a"] [3 "b"] [6 "c"]]
      result   => {1 "a", 3 "b", 6 "c"}
      
      Ran 2 tests containing 1 assertions.
      0 failures, 0 errors.
      

      当它与所有单元测试一起工作时,只需剪掉-spy 部分以留下正常的(let ...)form。


      请务必查看此list of documentation sources,尤其是 Clojure CheatSheet。

      【讨论】:

      • 谢谢。这里的过程很容易推理。我以前也没有听说过 Tupelo,确实很有用。
      【解决方案5】:

      可能是最简单(最易读)的版本:

      (def ml [{1 "a"} {2 "b"} {3 "c"}])
      (defn cumsum [l] (reductions + l))
      
      (let [m  (into (sorted-map) ml)]
        (zipmap  (cumsum (keys m)) (vals m)))
      
      ;; => {1 "a", 3 "b", 6 "c"}
      

      【讨论】:

      • @AlanThompson 谢谢!我将(into {} ml) 改进为(into (sorted-map) ml)
      • 它仍然有缺陷:[{2 "b"} {1 "a"} {3 "c"}] -> {1 "a", 3 "b", 6 "c"} 虽然它应该是{2 "b", 3 "a", 6 "c"} .. 你看:当地图没有按输入键排序时会导致意外结果。
      【解决方案6】:

      这个怎么样?

      (defn f [v]
            (zipmap (reductions + (mapcat keys v)) (mapcat vals v)))
      

      适用于地图的原始矢量:

      (f [{1 "a"} {2 "b"} {3 "c"}])
      
      ;; => {1 "a", 3 "b", 6 "c"}
      

      .. 以及不同长度的地图:

      (f [{1 "a"} {2 "b"} {3 "c" 4 "d"} {5 "e" 6 "f" 7 "g"}])
      
      ;; => {1 "a", 3 "b", 6 "c", 10 "d", 15 "e", 21 "f", 28 "g"}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-30
        • 1970-01-01
        • 2014-03-06
        • 1970-01-01
        • 1970-01-01
        • 2011-10-26
        • 2017-06-28
        相关资源
        最近更新 更多