对数组中的所有数字求和,直到达到某个值

Sum all numbers in array until a certain value is reached

我正在写一个函数,这是拼图的最后一块,我认为这很容易解决,但在修改 for 和 while 循环失败后,我尝试在网上查找它,但仍然找不到答案。我遇到了一些晦涩而复杂的解决方案,但我认为应该有一种更直接的方法来解决这个问题。例如,如果我有一个数组

[1, 2, 3, 5, 7, 9]

且参数为 10,函数应 return 6 (1 + 2 + 3),因为值的总和应 <= 10(或传递的任何数字)。如果参数是4,函数应该return 3 (1 + 2) 等等。

您可以使用 for 循环:

const arg = 10
const arr = [1, 2, 3, 5, 7, 9]
let res = 0;
const calc = (arr, limit) => {
  for (num of arr) {
    if (num + res > limit) {
      break;
    }
    res += num;
  }
  return res;
}
console.log(calc(arr, arg))

.reduce() 每个当前值 (cur) 添加到累加器 (acc) 并检查与限制 (max)。如果 acc + cur 小于限制,则 return acc+ cur,否则 return acc。根据 Spectric 的评论,如果数组碰巧乱序,则添加 .sort()

const array = [1,2,3,5,6,8];
const mixed = [0,7,3,8,2,1];
const A = 10;
const B = 15;
const closest = (arr, max) => {
  return arr.sort((a, b) => a - b).reduce((acc, cur) => 
    (acc + cur) > max ? acc : (acc + cur));  
}

console.log(closest(array, A));
console.log(closest(array, B));
console.log(closest(mixed, B));

一个有趣的方法是意识到我们想要弃牌(类似于 Array.prototype.reduce)但我们可以尽早逃避。 zer00ne 的答案是通过选择在每次迭代时检查条件,并在每次不满足条件时不断 return 计算累加器来做到这一点。这对很多人来说都很好 use-cases,但最好让它更明确。

我知道有两种方法可以做到这一点。一个是要有一些信号值,我们会 return —— 可能是一个符号 —— 说,“我们完成了,只是 return 累加器。”缺点是此功能现在取决于外部信号值。这并不可怕,而且通常可能是正确的解决方案。不难写,留作练习吧。

另一种技术是要求回调明确选择是继续迭代还是停止迭代,方法是为其提供 nextdone 函数。如果我们想继续,我们用下一个累加器值调用 next。如果我们完成了,我们就调用 done。这是一个版本:

const fold = (fn) => (a) => ([x, ...xs]) =>
  x == undefined ? a : fn (a, x, (r) => fold (fn) (r) (xs), () => a)

const sumUpTo = (n) => 
  fold ((a, x, next, done) => a + x > n ? done () : next (a + x)) (0)

console .log (sumUpTo (10) ([1, 2, 3, 5, 7, 9])) //=> 6
console .log (sumUpTo (4)  ([1, 2, 3, 5, 7, 9])) //=> 3
console .log (sumUpTo (10) ([1, 2, 3, 4, 5, 6])) //=> 10

sumUpTo 获取我们的总值,return 是一个获取数字列表的函数。它通过调用 fold 使用回调函数、初始值(0 求和)并最终传递我们的数字列表来实现。该回调完成了我们关心的工作。然后 fold 重复调用它,直到用完值或调用 done

我们可以分解上面的one-liner版本来专门关注回调,如果它更清楚的话:

const callback = (n) => (a, x, next, done) => 
  a + x > n 
    ? done () 
    : next (a + x)

const sumUpTo = (n) => fold (callback (n)) (0)

在我看来,这是一个非常优雅的模式。