使用 JavaScript reduce 来更新和添加到对象数组
Using JavaScript reduce to update and add to array of objects
我正在尝试解决 JavaScript 中的一个问题,并且相信使用 reduce
方法会是最优雅的。我有一组看起来像这样的对象:
let existingLots = [
{
id: 1,
title: 'one',
colour: 'red',
speed: 100
},
{
id: 2,
title: 'two',
colour: 'blue',
speed: 70
},
{
id: 3,
title: 'three',
colour: 'white',
speed: 120
},
{
id: 4,
title: 'four',
colour: 'yellow',
speed: 90
},
]
另一个数组如下所示:
let newLots = [
{
id: 1,
title: 'one',
colour: 'orange',
speed: 100,
owner: 'Ted'
},
{
id: 2,
title: 'two',
colour: 'blue',
speed: 75
},
{
id: 3,
title: 'three updated',
colour: 'white',
speed: 120,
},
{
id: 4,
title: 'four',
colour: 'yellow',
speed: 90
},
{
id: 5,
title: 'five',
colour: 'green',
speed: 50
},
]
如您所见,某些 ID 之间存在重叠。我想更新 existingLots
数组,这样如果一个对象与 newLots
数组中的对象共享相同的 id
,则该对象会更新为任何新的 properties/values在它的 newLots
对应物中。另外,我希望 newLots
中的所有对象(即 5
中 id
的对象)不在 existingObjects
中的对象添加到 existingObjects
数组。
我尝试了以下但没有达到预期的结果:
const res = existingLots.reduce((acc, obj) => {
let updatedObj = newLots.filter(newLot => newLot.id === obj.id);
// if object exists in currentLots, merge it
if(updatedObj) {
[...acc, {...obj, ...updatedObj}]
} else {
let newObj = !newLots.filter(newLot => newLot.id === obj.id);
[...acc, {...newObj}]
}
return acc
}, [])
我是 JavaScript 数组方法的新手,非常感谢您的帮助。
1) 您正在使用 filter 这将 return 一个过滤器元素数组
The filter() method creates a new array with all elements that pass
the test implemented by the provided function. - MDN
2) 此代码只是 push/add 数组中最后一个元素之后的所有对象,然后被丢弃,因为您没有将它们存储在任何地方
[...acc, {...obj, ...updatedObj}]
解决方案: 您可以使用 forEach 遍历 newLots
数组并将数据添加到 existingLots
元素
newLots.forEach((newLot) => {
let objExist = existingLots.find((o) => o.id === newLot.id);
if (objExist) {
for (let key in newLot) objExist[key] = newLot[key];
} else existingLots.push(newLot);
});
或
newLots.forEach((newLot) => {
let index = existingLots.findIndex((o) => o.id === newLot.id);
if (index !== -1) existingLots[index] = { ...existingLots[index], ...newLot };
else existingLots.push(newLot);
});
let existingLots = [
{
id: 1,
title: "one",
colour: "red",
speed: 100,
},
{
id: 2,
title: "two",
colour: "blue",
speed: 70,
},
{
id: 3,
title: "three",
colour: "white",
speed: 120,
},
{
id: 4,
title: "four",
colour: "yellow",
speed: 90,
},
];
let newLots = [
{
id: 1,
title: "one",
colour: "orange",
speed: 100,
owner: "Ted",
},
{
id: 2,
title: "two",
colour: "blue",
speed: 75,
},
{
id: 3,
title: "three updated",
colour: "white",
speed: 120,
},
{
id: 4,
title: "four",
colour: "yellow",
speed: 90,
},
{
id: 5,
title: "five",
colour: "green",
speed: 50,
},
];
newLots.forEach((newLot) => {
let index = existingLots.findIndex((o) => o.id === newLot.id);
if (index !== -1) existingLots[index] = { ...existingLots[index], ...newLot };
else existingLots.push(newLot);
});
console.log(existingLots);
我认为您唯一可以使用一些“魔法”的地方是查找。此代码在对象 id-s 和它们在实际数组中的索引之间创建一个 map
,然后遍历更新程序数组,使用 map
查找和更新现有对象,如果id
是全新的。
let existingLots = [{
id: 1,
title: 'one',
colour: 'red',
speed: 100
},
{
id: 2,
title: 'two',
colour: 'blue',
speed: 70
},
{
id: 3,
title: 'three',
colour: 'white',
speed: 120
},
{
id: 4,
title: 'four',
colour: 'yellow',
speed: 90
},
];
let newLots = [{
id: 1,
title: 'one',
colour: 'orange',
speed: 100,
owner: 'Ted'
},
{
id: 2,
title: 'two',
colour: 'blue',
speed: 75
},
{
id: 3,
title: 'three updated',
colour: 'white',
speed: 120,
},
{
id: 4,
title: 'four',
colour: 'yellow',
speed: 90
},
{
id: 5,
title: 'five',
colour: 'green',
speed: 50
},
];
let map = existingLots.reduce((acc, obj, idx) => acc.set(obj.id, idx), new Map());
for (let obj of newLots)
if (map.has(obj.id)) {
let idx = map.get(obj.id);
existingLots[idx] = {...existingLots[idx], ...obj};
} else
existingLots.push(obj);
console.log(existingLots);
更新程序部分实际上也可以在您的代码中工作,就像 filter()
总是给您一个数组一样,if(updatedObj)
应该是 if(updatedObj.length)
和 updatedObj
的用法将是 updatedObj[0]
。 acc =
(或简单的 return
)也不见了。
但是所有这些数组方法(filter()
、reduce()
、map()
)通常都在单个数组上工作,它们并不真正适合根据条件从另一个数组追加元素,因此second if
只是无法工作 - 为此,你最好使用一个简单的循环,因为这两个答案都建议,然后更新可能会在同一个循环中发生。
我正在尝试解决 JavaScript 中的一个问题,并且相信使用 reduce
方法会是最优雅的。我有一组看起来像这样的对象:
let existingLots = [
{
id: 1,
title: 'one',
colour: 'red',
speed: 100
},
{
id: 2,
title: 'two',
colour: 'blue',
speed: 70
},
{
id: 3,
title: 'three',
colour: 'white',
speed: 120
},
{
id: 4,
title: 'four',
colour: 'yellow',
speed: 90
},
]
另一个数组如下所示:
let newLots = [
{
id: 1,
title: 'one',
colour: 'orange',
speed: 100,
owner: 'Ted'
},
{
id: 2,
title: 'two',
colour: 'blue',
speed: 75
},
{
id: 3,
title: 'three updated',
colour: 'white',
speed: 120,
},
{
id: 4,
title: 'four',
colour: 'yellow',
speed: 90
},
{
id: 5,
title: 'five',
colour: 'green',
speed: 50
},
]
如您所见,某些 ID 之间存在重叠。我想更新 existingLots
数组,这样如果一个对象与 newLots
数组中的对象共享相同的 id
,则该对象会更新为任何新的 properties/values在它的 newLots
对应物中。另外,我希望 newLots
中的所有对象(即 5
中 id
的对象)不在 existingObjects
中的对象添加到 existingObjects
数组。
我尝试了以下但没有达到预期的结果:
const res = existingLots.reduce((acc, obj) => {
let updatedObj = newLots.filter(newLot => newLot.id === obj.id);
// if object exists in currentLots, merge it
if(updatedObj) {
[...acc, {...obj, ...updatedObj}]
} else {
let newObj = !newLots.filter(newLot => newLot.id === obj.id);
[...acc, {...newObj}]
}
return acc
}, [])
我是 JavaScript 数组方法的新手,非常感谢您的帮助。
1) 您正在使用 filter 这将 return 一个过滤器元素数组
The filter() method creates a new array with all elements that pass the test implemented by the provided function. - MDN
2) 此代码只是 push/add 数组中最后一个元素之后的所有对象,然后被丢弃,因为您没有将它们存储在任何地方
[...acc, {...obj, ...updatedObj}]
解决方案: 您可以使用 forEach 遍历 newLots
数组并将数据添加到 existingLots
元素
newLots.forEach((newLot) => {
let objExist = existingLots.find((o) => o.id === newLot.id);
if (objExist) {
for (let key in newLot) objExist[key] = newLot[key];
} else existingLots.push(newLot);
});
或
newLots.forEach((newLot) => {
let index = existingLots.findIndex((o) => o.id === newLot.id);
if (index !== -1) existingLots[index] = { ...existingLots[index], ...newLot };
else existingLots.push(newLot);
});
let existingLots = [
{
id: 1,
title: "one",
colour: "red",
speed: 100,
},
{
id: 2,
title: "two",
colour: "blue",
speed: 70,
},
{
id: 3,
title: "three",
colour: "white",
speed: 120,
},
{
id: 4,
title: "four",
colour: "yellow",
speed: 90,
},
];
let newLots = [
{
id: 1,
title: "one",
colour: "orange",
speed: 100,
owner: "Ted",
},
{
id: 2,
title: "two",
colour: "blue",
speed: 75,
},
{
id: 3,
title: "three updated",
colour: "white",
speed: 120,
},
{
id: 4,
title: "four",
colour: "yellow",
speed: 90,
},
{
id: 5,
title: "five",
colour: "green",
speed: 50,
},
];
newLots.forEach((newLot) => {
let index = existingLots.findIndex((o) => o.id === newLot.id);
if (index !== -1) existingLots[index] = { ...existingLots[index], ...newLot };
else existingLots.push(newLot);
});
console.log(existingLots);
我认为您唯一可以使用一些“魔法”的地方是查找。此代码在对象 id-s 和它们在实际数组中的索引之间创建一个 map
,然后遍历更新程序数组,使用 map
查找和更新现有对象,如果id
是全新的。
let existingLots = [{
id: 1,
title: 'one',
colour: 'red',
speed: 100
},
{
id: 2,
title: 'two',
colour: 'blue',
speed: 70
},
{
id: 3,
title: 'three',
colour: 'white',
speed: 120
},
{
id: 4,
title: 'four',
colour: 'yellow',
speed: 90
},
];
let newLots = [{
id: 1,
title: 'one',
colour: 'orange',
speed: 100,
owner: 'Ted'
},
{
id: 2,
title: 'two',
colour: 'blue',
speed: 75
},
{
id: 3,
title: 'three updated',
colour: 'white',
speed: 120,
},
{
id: 4,
title: 'four',
colour: 'yellow',
speed: 90
},
{
id: 5,
title: 'five',
colour: 'green',
speed: 50
},
];
let map = existingLots.reduce((acc, obj, idx) => acc.set(obj.id, idx), new Map());
for (let obj of newLots)
if (map.has(obj.id)) {
let idx = map.get(obj.id);
existingLots[idx] = {...existingLots[idx], ...obj};
} else
existingLots.push(obj);
console.log(existingLots);
更新程序部分实际上也可以在您的代码中工作,就像 filter()
总是给您一个数组一样,if(updatedObj)
应该是 if(updatedObj.length)
和 updatedObj
的用法将是 updatedObj[0]
。 acc =
(或简单的 return
)也不见了。
但是所有这些数组方法(filter()
、reduce()
、map()
)通常都在单个数组上工作,它们并不真正适合根据条件从另一个数组追加元素,因此second if
只是无法工作 - 为此,你最好使用一个简单的循环,因为这两个答案都建议,然后更新可能会在同一个循环中发生。