我试图获取一个数组并从中创建一个嵌套对象,其中数组中的每个项目都是上一个项目的属性。
我认为reduce
是做到这一点的方法,但是我发现reduce
很难掌握,而且我尝试做的所有事情都卡住了,因为我不知道该如何进入下一个层次。
JS: Reduce array to nested objects是一个类似的问题,但是尝试了许多变体后,我仍然无法使用。
const myArray = ['one', 'two', 'three'];
// Intended Output (note, the staticCount is always 1)
{
one: {
staticCount: 1,
two: {
staticCount: 1,
three: {
staticCount: 1
}
}
}
}
答案 0 :(得分:5)
某些工作需要Array.prototype.reduceRight
:
const myArray = ['one', 'two', 'three']
const nestNode = (acc, key) => {
acc.staticCount = 1
return { [key]: acc }
}
console.log(myArray.reduceRight(nestNode, {}))
让我们看一下reduceRight
(以及扩展名reduce
):
我将迭代器函数定义移出了对reduceRight
的调用,以使该示例更易于讨论(请参见nestNode
)。
reduce
和reduceRight
相似:
每个函数都有两个参数,一个迭代器函数和一个该函数的累加器的初始值。第二个参数是可选的,但在这里我将忽略它。
每个函数都会迭代调用它们的数组中的所有项目,并使用四个参数(累加器,数组中的当前项目,当前迭代)为数组中的每个项目调用迭代器函数计数以及调用了reduce
的整个数组。最后两个参数在这里无关紧要(我很少使用它们)。
首次调用迭代器函数时,它将传递给您提供给reduce
或reduceRight
(初始累加器值)的第二个参数。然后,它将传递上一步中迭代器函数返回的内容。
因为我认为reduce
(以及扩展名reduceRight
)是值得理解的功能强大的抽象,所以我将逐步介绍代码示例中的前两个步骤:
在迭代的第一步,我们的迭代器函数将这样调用:nestNode(acc = {}, key = 'three')
。在nestNode
内,我们向staticCount
添加一个acc
属性,并将其设置为1
,得到acc = { staticCount: 1 }
。然后,我们创建并返回一个名为'three'
的属性,其值等于acc
的新对象。 nestNode
在第一步中返回的值为{ three: { staticCount: 1 } }
,在第二步中将用该值调用nestNode
。
在迭代的第二步中,我们的迭代器函数将这样调用:nestNode(acc = { three: { staticCount: 1 } }, key = 'two')
。同样,我们将staticCount
属性添加到acc
并将其设置为1
,从而得到acc = { three: { staticCount: 1 }, staticCount: 1 }
。然后,我们创建并返回一个名为'two'
的属性,其值等于acc
的新对象。我们返回的值为{ two: { three: { staticCount: 1 }, staticCount: 1 } }
。同样,此值将在下一步中使用。
我将跳过最后一步,因为我希望详细了解一下前两个步骤足以使事情变得简单。如果您还有其他问题,或者仍然不清楚或感到困惑,请告诉我。
reduce
(和reduceRight
)是功能强大且灵活的工具,值得学习和使用。
作为尾声,我将在每一步之后为您提供迭代器函数的返回值:
{ three: { staticCount: 1 } }
{ two: { three: { staticCount: 1 } }, staticCount: 1 }
{ one: { two: { three: { staticCount: 1 } }, staticCount: 1 }, staticCount: 1 }
答案 1 :(得分:2)
感谢Tex使我将reverse().reduce()
替换为reduceRight
:
['one', 'two', 'three'].reduceRight((a, c) => ({[c]: { staticCount: 1, ...a }}), {});
答案 2 :(得分:2)
reduce
与map
一样,将循环访问数组中的每个项目并返回结果。关键区别在于map
将返回与原始大小相等的数组,并且您进行了任何修改。 reduce
采用所谓的accumulator
并将其作为最终结果返回。
reduce()
具有两个参数:
function()
accumulator
的起始值您提供的function()
具有三个值:
accumulator
的值关于accumulator
的最重要的了解是,它将变成您的function()
返回值的值,而您的函数 ALWAYS 必须返回某些值,否则accumulator
在下一个循环中将是未定义的。
遵循问题的解决方案是使用reduce
的基本示例。
const myArray = ['one','two','three'];
const result = {};
myArray.reduce((accumulator, num) => {
accumulator[num] = { staticCount: 1}
return accumulator[num];
}, result);
console.log(result);
此处提供的reduce
解决方案每秒可执行760万次操作,而reduceRight
每秒可执行220万次操作。
https://jsperf.com/reduceright-vs-reduce/
var numbers = [1, 2, 3, 4, 5];
// Reduce will assign sum whatever
// the value of result is on the last loop
var sum = numbers.reduce((result, number) => {
return result + number;
}, 0); // start result at 0
console.log(sum);
var numbers = [1, 2, 3, 4, 5];
// Here we're using the iterator, and
// assinging "too much" to sum if there
// are more than 4 numbers.
var sum = numbers.reduce((result, number, i) => {
if (i >= 4) return "too much";
return result + number;
}, 0);
console.log(sum);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
答案 3 :(得分:1)
只使用减少。之所以有效,是因为对象是通过引用传递的。
const myArray = ['one', 'two', 'three'];
const newObject = {};
myArray.reduce((acummulator, element) => {
acummulator[element] = {
staticCount: 1
};
return acummulator[element];
}, newObject);
// Intended Output (note, the staticCount is always 1)
console.log(newObject);
了解有关减少here的信息。
答案 4 :(得分:1)
诀窍不是从一个空的对象开始,而是从一些声明的变量开始。然后只需将新的子项作为下一个递归的集合向下传递。
参考文献已更新,您可以再次打印根目录。
const myArray = ['one', 'two', 'three'];
const root = {};
myArray.reduce( (agg, c) => {
agg[c] = { staticCount: 1 };
return agg[c];
}, root );
console.log( root );
答案 5 :(得分:1)
这也可以通过递归函数来实现:
const createObj = (keys) => keys.length > 0 && ({
[keys[0]]: {
staticCount: 1,
...createObj(keys.slice(1))
}
});
console.log(createObj(['one', 'two', 'three']));