简体   繁体   English

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

[英]Sum all numbers in array until a certain value is reached

I'm writing a function and this is the last piece of the puzzle, which I thought would be easy to deal with, but after some unsuccessful tinkering with for and while loops, I tried looking it up online and still couldn't find an answer.我正在编写一个函数,这是拼图的最后一块,我认为这很容易处理,但是在对 for 和 while 循环进行了一些不成功的修补后,我尝试在网上查找它,但仍然找不到回答。 I came across some obscure and complex solutions, but I think there should be a more straightforward way to solve this.我遇到了一些晦涩难懂和复杂的解决方案,但我认为应该有更直接的方法来解决这个问题。 For example, if I have an array例如,如果我有一个数组

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

And the argument is 10, the function should return 6 (1 + 2 + 3), because the sum of the values should be <= 10 (or whatever number is passed).并且参数是 10,函数应该返回 6 (1 + 2 + 3),因为值的总和应该 <= 10(或传递的任何数字)。 If the argument is 4, the function should return 3 (1 + 2) and so on.如果参数为 4,则函数应返回 3 (1 + 2),依此类推。

You can use a for loop:您可以使用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() each current value ( cur ) added to the accumulator ( acc ) and checked vs. the limit ( max ). .reduce()每个当前值 ( cur ) 添加到累加器 ( acc ) 并检查与限制 ( max ) 的对比。 If acc + cur is less than limit then return acc+ cur , otherwise return acc .如果acc + cur小于 limit 则返回acc+ cur ,否则返回acc Added .sort() if the array happens to be out of order, as per Spectric's comment.根据 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));

One interesting approach is to realize that we want to do a fold (something like Array.prototype.reduce ) but one which we can escape early.一种有趣的方法是意识到我们想做一个折叠(类似于Array.prototype.reduce ),但我们可以提前逃脱。 The answer from zer00ne does this by choosing to check the condition on every iteration, and just continually returning the accumulator each time the condition is not met. zer00ne 的答案是选择在每次迭代时检查条件,并且每次不满足条件时不断返回累加器。 That's fine for many use-cases, but it would be nice to make it more explicit.这对许多用例来说都很好,但让它更明确会更好。

I know of two ways to do this.我知道有两种方法可以做到这一点。 One is to have some signal value that we would return -- probably a symbol -- to say, "We're done, just return the accumulator."一种是有一些我们会返回的信号值——可能是一个符号——说,“我们完成了,只需返回累加器。” The downside is that this function now depends on that external signal value.缺点是这个函数现在依赖于外部信号值。 It's not terrible, and often might be the right solution.这并不可怕,而且通常可能是正确的解决方案。 It's not hard to write, and I'll leave it as an exercise.写起来不难,我把它留作练习。

The other technique is to require the callback to explicitly choose whether to continue the iteration or stop by supplying it with next and done functions.另一种技术是要求回调明确选择是继续迭代还是通过提供nextdone函数来停止。 If we want to continue, we call next with the next accumulator value.如果我们想继续,我们用下一个累加器值调用next If we're finished, we just call done .如果我们完成了,我们只需调用done Here's a version of that:这是一个版本:

 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 takes our total value and returns a function that takes a list of numbers. sumUpTo接受我们的总值并返回一个接受数字列表的函数。 It does this by calling fold using a callback function, the initial value ( 0 for a sum), and eventually passing our list of numbers.它通过使用回调函数调用fold来实现这一点,初始值(总和为0 ),并最终传递我们的数字列表。 That callback does the work we care about.该回调完成了我们关心的工作。 Then fold repeatedly calls it until it runs out of values or done is called.然后fold重复调用它,直到它用完值或调用done

We can break down the one-liner version above to focus specifically on the callback, if it makes it more clear:如果它更清楚,我们可以分解上面的单行版本以专门关注回调:

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

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

It's a very elegant pattern, to my mind.在我看来,这是一个非常优雅的模式。

Quickest way with smallest code footprint:代码占用最少的最快方法:

 const dataset = [1, 2, 3, 5, 7, 9] const getMaxSum = (dataset, max) => { var sum = 0, num; for( num of dataset ) { if( sum + num > max ) break // very important to break once satisfied sum += num } return sum } console.log( getMaxSum(dataset, 10) ) console.log( getMaxSum(dataset, 20) )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM