Javascript 将 Reduce、Map 和 Concat 与数组结合使用的嵌套函数

Javascript Nested Functions Using Combination of Reduce, Map and Concat with an Array

谁能给我解释一下这段代码是怎么来的:

const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
console.log(powerset(["dog", "pig"]));

return这个数组输出到控制台了吗?

0: []
1: ["dog"]
2: ["pig"]
3: (2) ["pig", "dog"]
length: 4

重点是从数组中获取元素,然后 return 这些元素的所有可能组合。我了解 reduce 函数、连接和映射,但我很难理解如何应用这些嵌套函数以及以什么顺序获得此输出。任何人都可以引导我了解每个 运行-through 函数发生了什么?

首先,将常量转化为函数:

function powerset(arr){
  return arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]])
}

我们知道reduce会循环遍历元素,放入累加器a。同时,它也会对 v 做 'something' 的值。那么,让我们深入挖掘一下:

a.concat(a.map(r => [v].concat(r)))

在这里,它获取累加器并向其添加一个数组。但是数组是什么?这是:

a.map(r => [v].concat(r))

现在我们可以看到它获取了 a 的每个元素,并且基本上将值 v 压入其中。

向后工作,现在我们可以看到 a 开始为 [[]],然后与从 a.map(r => [v].concat(r)) 输出的数组合并。这恰好是 arr 的第一个元素。所以,它变成了 [[], [first_element]].

重复此操作,我们可以看到每次它都获取一个元素,将其添加到累加器中的每个子数组,获取所有这些数组,然后将其添加回累加器。所以现在,您拥有所有包含示例元素 el 和不包含示例元素 el 的集合。重复,你有所有可能的组合。

将代码视为单独的函数可能会有所帮助:

function powerset(arr) {
  const initial = [[]];
  return arr.reduce(reduceFn, initial);

  function reduceFn(accumulatedValue, item) {
    // item will be "dog" or "pig"
    // accumulatedValue will start as [[]] and be equal to the result of the previous call of reduceFn by .reduce()
    const concatenatedAccumulation = accumulatedValue.map(function mapFn(e) {
      return [item].concat(e) // i.e. [item, ...e]
    });
    return accumulatedValue.concat(concatenatedAccumulation);
  }
}

arr.reduce 的执行看起来像这样(读作 call(): result):

  1. reduceFn(accumulatedValue = [[]], item = 'dog'): [[], ['dog']]
    • accumulatedValue.map: mapFn(e = []): [['dog']]
      • return [项目].concat: ['dog'].concat([]): ['dog']
    • return accumulatedValue.concat: return [[]].concat([['pig']])
  2. reduceFn(accumulatedValue = [[], ['dog']], item = 'pig'): [[], ['dog'], ['pig'], ['pig', 'dog']]
    • accumulatedValue.map: mapFn(e = [[], ['dog']]): [['pig'], ['pig', 'dog']]
      • return [项目].concat: ['pig'].concat([]): ['pig']
      • return [项目].concat: ['pig'].concat(['dog']): ['pig', 'dog']
    • return accumulatedValue.concat: return [[], ['dog']].concat([['pig'], ['pig', 'dog']])

已回答!这是原始代码,以及我对正在发生的事情的新理解:

const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
console.log(powerset(["dog", "pig"]));

1.) reduce 函数正在接受累加器 a,它以我们的初始化器 [[]] 和数组 powerset 中的第一个值 v 开始, 即 dog.

2.) 当我们通过 a 进行映射时,我们 r 的第一个值是带有子数组 [[]] 的空数组。当您执行 [dog].concat([[]]) 时,您最终只会得到 [dog].

3.) 然后,你有 a.concat(dog),所以你最终得到 [[], [dog]]。您的新累加器或 a 值现在是 [[], [dog]].

4.) reduce函数的下一个循环,累加器a[[], [dog]]v是我们powerset数组中的第二项,pig.

5.) 再次映射到 a。第一个循环将是 pig.concat([])。你只会得到 [pig].

6.) 下一个循环将是 pig.concat([dog]),所以你得到 [pig, dog].

7.) 现在,再次执行 a.concat。因为我们的新 a[[], [dog]],我们现在添加我们的两个新结果以获得 [[], [dog], [pig], [pig, dog]].

这就是我们最终得到“猪、狗”的所有不同组合的方式。