有人可以向我解释一下这段代码是如何做到的:
const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
console.log(powerset(["dog", "pig"]));
在控制台中返回此数组输出?
0: []
1: ["dog"]
2: ["pig"]
3: (2) ["pig", "dog"]
length: 4
重点是从数组中获取元素并返回这些元素的所有可能组合。我理解reduce函数,连接和映射,但我很难理解这些嵌套函数是如何应用的以及以什么顺序获得此输出。有人能够引导我了解函数的每次运行中发生了什么吗?
将代码视为单独的函数可能会有所帮助:
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
):
reduceFn(accumulatedValue = [[]], item = 'dog'): [[], ['dog']]
- 累积价值地图:
mapFn(e = []): [['dog']]
- 返回 [项目].concat:
['dog'].concat([]): ['dog']
- 返回 [项目].concat:
- return 累加值:
return [[]].concat([['pig']])
- 累积价值地图:
reduceFn(accumulatedValue = [[], ['dog']], item = 'pig'): [[], ['dog'], ['pig'], ['pig', 'dog']]
- 累积价值地图:
mapFn(e = [[], ['dog']]): [['pig'], ['pig', 'dog']]
- 返回 [项目].concat:
['pig'].concat([]): ['pig']
- 返回 [项目].concat:
['pig'].concat(['dog']): ['pig', 'dog']
- 返回 [项目].concat:
- return 累加值.concat:
return [[], ['dog']].concat([['pig'], ['pig', 'dog']])
- 累积价值地图:
首先,获取常量并将其转换为函数:
function powerset(arr){
return arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]])
}
我们知道reduce
会循环穿过元素并将它们放入a
,累加器。同时,它还会对v
值做"某事"。因此,让我们更深入地挖掘:
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
的集合。重复,你有所有可能的组合。
回答!这是原始代码,以及我对正在发生的事情的新理解:
const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
console.log(powerset(["dog", "pig"]));
1.) reduce函数正在接受累加器a
,它从我们的初始值设定项[[]]
开始,第一个值v
数组powerset
,即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]]
。
这就是我们最终得到"猪,狗"的所有不同组合的方式。