我正在努力将一系列“扁平”对象转换为压缩但嵌套的版本:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
/*
desiredResult = [
{name: 'one', id:100, things: [
{thing: 1}, {thing: 2}, {thing:4}
]},
{name: 'two', id:200, things: [
{thing: 5}
]}
]
*/
// THIS DOES NOT WORK
const result = startingArray.reduce((acc, curr) => {
if (acc.name) {
acc.things.push(curr.thing)
}
return { name: curr.name, id: curr.id, things: [{thing: curr.thing}] };
}, {});
我不明白什么?!
答案 0 :(得分:2)
在reduce回调中,acc
不是“数组的每个元素”(curr
就是)或“结果中的匹配元素”(您必须自己确定),这是每次调用该函数都会转换的累积对象。
也就是说,当您return { name: curr.name, id: curr.id, things: [{thing: curr.thing}] };
时,它将acc
设置为该对象以进行下一次迭代,并丢弃之前包含在其中的任何数据-acc.name
将永远保存姓氏反复出现,结果永远不会累积到任何有意义的地方。
您想要做的是将结果累加到一个数组中(因为这是您想要的输出),请确保每次迭代都返回该数组:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const result = startingArray.reduce((acc, curr) => {
let existing = acc.find(o => o.id == curr.id);
if(!existing) acc.push(existing = { name: curr.name, id: curr.id, things: [] });
existing.things.push({thing: curr.thing});
return acc;
}, []);
console.log(result);
由于需要使用结果格式,因此涉及许多acc.find()
调用,这很昂贵-您可以使用此技巧以简洁的方式解决此问题,将累加器数组的第一个元素用作引用的ID(还具有ES6解构功能):
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const result = startingArray.reduce((acc, {name, id, thing}) => {
if(!acc[0][id])
acc.push(acc[0][id] = { name, id, things: [] });
acc[0][id].things.push({thing});
return acc;
}, [{}]).slice(1); //slice off the mapping as it's no longer needed
console.log(result);
答案 1 :(得分:1)
确定,提供其他方法。关键是您要累积一个对象,以后只取值,所以得到一个数组:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const res = startingArray.reduce((acc, curr) => {
if (acc[curr.name]) {
acc[curr.name].things.push({thing: curr.thing})
} else {
acc[curr.name] = {
name: curr.name,
id: curr.id,
things: [{thing: curr.thing}]
}
}
return acc
}, {})
console.log(Object.values(res))