【问题标题】:reduce-while function in clojure?clojure中的reduce-while函数?
【发布时间】:2013-12-22 02:02:45
【问题描述】:

我是 Clojure 编程的新手,想知道执行以下操作的惯用方式是什么:

  1. 我想对一组数字nums求和,其中可能包含大量数字,假设只有正数。

  2. 如果总和非常大,我不在乎确切的总和。例如,如果数字的总和大于 9999,我会简单地返回 10000,而不会将剩余的数字相加。

如果我用一些 OO 语言如 Java 来实现它,我可能会这样做:

private int sum(int[] nums) {
  int sum = 0;
  for(int n : nums) {
    if(sum > 9999) {
      sum = 10000;
      break;
    } else {
      sum += n;
    }
  }
  return sum;
}

Clojure 中的简单实现可能如下所示:

(let [sum (reduce + nums)]
   (if (> sum 9999) 10000 sum))

但是,这似乎浪费了一些 CPU 资源来汇总整个数字集合,这是不希望的。我正在寻找像 take-while 功能但用于减少的东西,但找不到它。有没有类似的东西:

(reduce-while pred f val coll)

或者有没有其他 Clojure 惯用的方法来解决这个问题?我认为该解决方案可以应用于一组需要类似逻辑的问题。

感谢任何评论。谢谢。

【问题讨论】:

    标签: clojure


    【解决方案1】:

    如果您使用 Clojure 1.5.x,那么您可以利用 new reduced function

    (reduce #(if (> %1 9999) (reduced 10000) (+ %1 %2)) nums)
    

    【讨论】:

    • 谢谢。这正是我正在寻找的。我在 4clojure.com 做一些练习,但它似乎还不支持 Clojure 1.5 :(
    【解决方案2】:

    一个鲜为人知的 Clojure 函数似乎是 reductions。它将为您提供计算的所有中间结果:

    (reductions + (range 4)) ;; => (0 1 3 6)
    (reduce + (range 4))     ;; => 3
    

    reductions'结果序列的最后一个元素将是减少的值。有多种方法可以强制执行您的谓词,例如使用some:

    (let [sums (reductions + nums)]
      (if (some #(> % 9999) sums)
        10000
        (last sums)))
    

    @leonid-beschastny 给出的reduce/reduced 版本可能更快(没有惰性序列开销、reducers 等),但这个版本也可以在早期的 Clojure 版本中使用。

    【讨论】:

    • 关于第一个代码块 - 值应分别为 (0 1 3 6) 和 6
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-13
    • 2022-11-14
    • 2015-07-18
    • 2016-08-29
    • 1970-01-01
    • 1970-01-01
    • 2019-07-18
    相关资源
    最近更新 更多