对数组中的所有数字求和,直到达到某个值
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 累加器。”缺点是此功能现在取决于外部信号值。这并不可怕,而且通常可能是正确的解决方案。不难写,留作练习吧。
另一种技术是要求回调明确选择是继续迭代还是停止迭代,方法是为其提供 next
和 done
函数。如果我们想继续,我们用下一个累加器值调用 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)
在我看来,这是一个非常优雅的模式。
我正在写一个函数,这是拼图的最后一块,我认为这很容易解决,但在修改 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 累加器。”缺点是此功能现在取决于外部信号值。这并不可怕,而且通常可能是正确的解决方案。不难写,留作练习吧。
另一种技术是要求回调明确选择是继续迭代还是停止迭代,方法是为其提供 next
和 done
函数。如果我们想继续,我们用下一个累加器值调用 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)
在我看来,这是一个非常优雅的模式。