【问题标题】:Javascript - Counting array elements by reduce method until specific value occurs doesn't give a correct outputJavascript - 通过reduce方法计算数组元素直到出现特定值不会给出正确的输出
【发布时间】:2020-05-29 17:24:14
【问题描述】:
const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total)=>(num==0 ? total : total+num), 0) 
console.log(sum(arr, 0))

请检查我怎样才能使它工作。犯了一些错误,但不知道具体是什么。输出是函数而不是结果。

【问题讨论】:

  • 什么是x?您从未定义过该变量。
  • 所以现在,如果您调用sum 并将0 作为第二个参数传递,您将不会计算任何东西...
  • 你的预期输出是什么?
  • 知道了,但是在出现特定值(第二个参数)之前,我还能如何计算? @VLAZ
  • @Nick 是 11。数组中出现参数 0 之前的数字之和。

标签: javascript arrays reduce


【解决方案1】:

这在.reduce 中执行起来很尴尬,因为它通过了整个 数组。如果我们做一个简单的实现,你会发现问题:

const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total, x)=>(num==x ? total : total+x), 0) 
console.log(sum(arr, 0))

我们现在正确地进行检查 - 当x 为零(num 的值)时,num==x 将返回 true。然而,结果是错误的,因为它只返回trueonce,但任何其他迭代仍然是true。这是相同的事情,更多的日志记录描述了过程的每个步骤:

const arr = [5,6,0,7,8];
const sum = (arr,num) => arr.reduce((total, x)=> {
  const boolCheck = num==x;
  const result = boolCheck ? total : total+x;
  console.log(
`total: ${total}
num: ${num}
x: ${x}
boolCheck: ${boolCheck}
result: ${result}`);

    return result;
  }, 0) 
console.log(sum(arr, 0))

因此,您需要添加一些在迭代之间持续存在的标志,这样它就不会丢失。

一种选择是在reduce 回调中更改一个外部标志:

const arr = [5,6,0,7,8];
const sum = (arr,num) => {
  let finished = false;
  return arr.reduce((total, x) => {
    if(x === num)
      finished = true;
      
    return finished ? total : total+x;
  }, 0)
}
console.log(sum(arr, 0))

或者,您可以在 reduce 回调内部使用该标志,并在调用之间传递它。它最终以相同的方式工作,但使回调函数变得纯粹。以一些非正统的结构为代价:

const arr = [5,6,0,7,8];
const sum = (arr,num) => {
  return arr.reduce(({total, finished}, x) => {
    if(x === num)
      finished = true;

    total = finished ? total : total+x;

    return {total, finished};
  }, {total: 0, finished: false})
  .total
}
console.log(sum(arr, 0))

如果您想使用reduce,但您可以使用其他方法,那么您可以使用Array#indexOf 查找值的第一个实例,并使用Array#slice 查找包含目标值之前的任何值的数组价值:

const arr = [5,6,0,7,8];
const sum = (arr,num) => {
  const endIndex = arr.indexOf(num);
  
  return arr.slice(0, endIndex)
    .reduce((total, x)=> total+x, 0)
}
console.log(sum(arr, 0))

或作为一个链式表达式:

const arr = [5,6,0,7,8];
const sum = (arr,num) => arr
  .slice(0, arr.indexOf(num))
  .reduce((total, x)=> total+x, 0);

console.log(sum(arr, 0))

其他库可能有一个 takeUntiltakeWhile 操作,这更接近您想要的 - 它为您提供一个数组开始直到给定的值或条件。然后你可以减少它的结果。

这是一个使用Lodash#takeWhile的示例

通过这里使用链接,Lodash 会做惰性求值,所以它只会遍历一次数组,而不是扫描一次找到结束索引并再次遍历数组进行求和。

const arr = [5,6,0,7,8];
const sum = (arr,num) => _(arr)
  .takeWhile(x => x !== num)
  .reduce((total, x)=>total+x, 0)

console.log(sum(arr, 0))
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>

请注意,如果您正在使用 Lodash,那么您不妨使用_.sum()。我上面不是为了说明通用 takeUntil/takeWhile 的外观。

const arr = [5, 6, 0, 7, 8];
const sum = (arr, num) => _(arr)
  .takeWhile(x => x !== num)
  .sum()

console.log(sum(arr, 0))
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>

【讨论】:

  • 非常感谢您的澄清!总新手,认为如果通过 reduce 来编写代码会更少,但它似乎和你通过'for loops' 做的代码一样:)))
  • 您也可以对数组进行切片。这将避免有一个非常复杂的reduce 逻辑。我已经对此添加了注释。
  • 天哪,伙计,有很多选择要做 - 你是老板!再次感谢您!
  • 唯一的问题是我很难理解使用“切片”方法的代码
  • .slice 获取数组的一部分一个索引,另一个索引。第一个参数是0,所以它从头开始。第二个参数(实际上)是.indexOf(0) 的结果,它是数组中第一个零的位置。因此,这就像手动实现 takeUntil 功能,您可以在其中获取从开始到第一个零的数组部分。
【解决方案2】:

由于您需要在数组的中途停止对值求和,这可能最简单地使用 for 循环实现:

const arr = [5, 6, 0, 7, 8];
const num = 0;

let sum = 0;
for (let i = 0; i < arr.length; i++) {
  if (arr[i] == num) break;
  sum += arr[i];
}
console.log(sum);

如果你想使用reduce,你需要保留一个标志,表明你是否看到了num的值,这样你就可以停止从数组中添加值:

const arr = [5, 6, 0, 7, 8];

const sum = (arr, num) => {
  let seen = false;
  return arr.reduce((c, v) => {
    if (seen || v == num) {
      seen = true;
      return c;
    }
    return c + v;
  }, 0);
}

console.log(sum(arr, 0));
console.log(sum(arr, 8));

【讨论】:

  • 谢谢 Nick,但我想知道如何通过 reduce 来实现。
  • @ElMuchacho 查看我的编辑,我使用reduce添加了另一段代码
【解决方案3】:

这样称呼它:

console.log(sum(arr, 0)());

【讨论】:

    【解决方案4】:

    你需要括号来执行函数()

    sum(arr, 0)
    

    如果没有括号,则将函数的引用存储在变量中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-14
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 2019-09-24
      • 2015-12-02
      • 2021-11-29
      相关资源
      最近更新 更多