使用 reduce 从简单数组到二维数组(ft. logical AND &&)

From simple array to 2D array using reduce (ft. logical AND &&)

我需要将一个简单的平面数组“转换”为二维数组,然后我继续查看它对参数的说明。
我试图重新创建 this answer 的代码,但我得到了这个错误:

console.log(array.reduce((twoDArray, n, i) => (i % 3 == 0 ? twoDArray.push([n]) : twoDArray[twoDArray.length-1].push(n)), []));
                                                                                                                ^
TypeError: Cannot read property 'push' of undefined

问题是我没有在箭头函数的末尾添加&& twoDArray。在这里你可以看到:

let array = [1,2,3,4,5,6,7,8,9];

// this works
console.log(array.reduce((twoDArray, n, i) => (i % 3 == 0 ? twoDArray.push([n]) : twoDArray[twoDArray.length-1].push(n)) && twoDArray, []));

// here the second push() throws an error
console.log(array.reduce((twoDArray, n, i) => (i % 3 == 0 ? twoDArray.push([n]) : twoDArray[twoDArray.length-1].push(n)), []));

现在有几件事我不明白,即:

这是必需的,因为 push returns 数组的新长度 - 但累加器需要是 数组 ,而不是长度。

没有 &&,并将代码缩进多行以使其更清楚发生了什么,第二个代码等同于:

let array = [1, 2, 3, 4, 5, 6, 7, 8, 9];

// here the second push() throws an error
console.log(array.reduce((twoDArray, n, i) => {
  return (i % 3 == 0 ? twoDArray.push([n]) : twoDArray[twoDArray.length - 1].push(n))
}, []));

同于:

let array = [1, 2, 3, 4, 5, 6, 7, 8, 9];

// here the second push() throws an error
console.log(array.reduce((twoDArray, n, i) => {
  return (
    i % 3 == 0
      ? twoDArray.push([n])
      : twoDArray[twoDArray.length - 1].push(n)
  );
}, []));

现在,问题应该很清楚了:无论进入哪个条件,回调的计算结果都是

  return (
    i % 3 == 0
      ? someNumber
      : someNumber
  );

因为 .push 计算出数组的新长度。

向其添加 && twoDArray 使回调看起来像:

  return (
    i % 3 == 0
      ? someNumber
      : someNumber
  ) && twoDArray;

因此返回 twoDArray 而不是数字。

Shouldn't the code throw an error before to reach the &&?

确实如此。在second迭代时抛出错误,当twoDArray[twoDArray.length-1]时,当twoDArray是一个数字时,计算结果为undefined,所以不能推到。但是 twoDArray 是一个数字而不是数组的问题是由先前(第一次)迭代的尾端代码引起的:缺少 && twoDArray;.

这样的代码非常混乱。如果代码难以阅读,请尽量不要将代码压缩成一行。另一个问题是,当累加器在每次迭代中都是同一个对象时,可以说 .reduce 是不合适的。考虑做这样的事情:

let array = [1, 2, 3, 4, 5, 6, 7, 8, 9];

const twoDArray= [];
array.forEach((n, i) => {
  i % 3 == 0
    ? twoDArray.push([n])
    : twoDArray[twoDArray.length - 1].push(n);
});
console.log(twoDArray);

并使用if/else代替条件运算符:

let array = [1, 2, 3, 4, 5, 6, 7, 8, 9];

const twoDArray= [];
array.forEach((n, i) => {
  if (i % 3 === 0) twoDArray.push([n])
  else twoDArray[twoDArray.length - 1].push(n);
});
console.log(twoDArray);