JavaScript 按 id 合并对象
JavaScript merging objects by id
Javascript中合并两个数组的正确方法是什么?
我有两个数组(例如):
var a1 = [{ id : 1, name : "test"}, { id : 2, name : "test2"}]
var a2 = [{ id : 1, count : "1"}, {id : 2, count : "2"}]
我希望能够得到这样的东西:
var a3 = [{ id : 1, name : "test", count : "1"},
{ id : 2, name : "test2", count : "2"}]
其中两个数组基于"id"字段连接,并且只是添加额外的数据。
我尝试使用 _.union
来执行此操作,但它只是将第二个数组中的值覆盖到第一个数组中
ES6 解决方案
const a3 = a1.map(t1 => ({...t1, ...a2.find(t2 => t2.id === t1.id)}))
这应该可以解决问题:
var mergedList = _.map(a1, function(item){
return _.extend(item, _.findWhere(a2, { id: item.id }));
});
这假设 a1 中第二个对象的 id 应该是 2 而不是"2"
假设 ID 是字符串并且顺序无关紧要,您可以
- 创建哈希表。
- 迭代两个数组并将数据存储在按 ID 索引的哈希表中。如果已经有一些数据具有该 ID,请使用
Object.assign
更新它(ES6,可以填充)。 - 获取包含哈希映射值的数组。
var hash = Object.create(null);
a1.concat(a2).forEach(function(obj) {
hash[obj.id] = Object.assign(hash[obj.id] || {}, obj);
});
var a3 = Object.keys(hash).map(function(key) {
return hash[key];
});
在 ECMAScript6 中,如果 ID 不一定是字符串,可以使用 Map
:
var hash = new Map();
a1.concat(a2).forEach(function(obj) {
hash.set(obj.id, Object.assign(hash.get(obj.id) || {}, obj))
});
var a3 = Array.from(hash.values());
ES6 简化了这个:
let merge = (obj1, obj2) => ({...obj1, ...obj2});
请注意,重复的键将被合并,第二个对象的值将优先,第一个对象的重复值将被忽略。
例:
let obj1 = {id: 1, uniqueObj1Key: "uniqueKeyValueObj1", repeatedKey: "obj1Val"};
let obj2 = {id: 1, uniqueObj2Key: "uniqueKeyValueObj2", repeatedKey: "obj2Val"};
merge(obj1, obj2)
// {id: 1, uniqueObj1Key: "uniqueKeyValueObj1", repeatedKey: "obj2Val", uniqueObj2Key: "uniqueKeyValueObj2"}
merge(obj2, obj1)
// {id: 1, uniqueObj2Key: "uniqueKeyValueObj2", repeatedKey: "obj1Val", uniqueObj1Key: "uniqueKeyValueObj1"}
完整的解决方案(使用洛达什,而不是下划线)
var a1 = [{ id : 1, name : "test"}, { id : 2, name : "test2"}]
var a2 = [{ id : 1, count : "1"}, {id : 2, count : "2"}]
var merge = (obj1, obj2) => ({...obj1, ...obj2});
_.zipWith(a1, a2, merge)
(2) [{…}, {…}]
0: {id: 1, name: "test", count: "1"}
1: {id: 2, name: "test2", count: "2"}
如果你有一个数组要合并,你可以这样做:
var arrayOfArraysToMerge = [a1, a2, a3, a4]; //a3 and a4 are arrays like a1 and a2 but with different properties and same IDs.
_.zipWith(...arrayOfArraysToMerge, merge)
(2) [{…}, {…}]
0: {id: 1, name: "test", count: "1", extra1: "val1", extra2: 1}
1: {id: 2, name: "test2", count: "2", extra1: "val2", extra2: 2}
reduce version。
var a3 = a1.concat(a2).reduce((acc, x) => {
acc[x.id] = Object.assign(acc[x.id] || {}, x);
return acc;
}, {});
_.values(a3);
我认为这是函数式语言的常见做法。
已经有很多很棒的答案,我再添加一个来自我昨天需要解决的一个实际问题。
我有一个带有用户 ID 的消息数组,以及一个包含用户名和其他详细信息的用户数组。这就是我设法将用户详细信息添加到消息中的方式。
var messages = [{userId: 2, content: "Salam"}, {userId: 5, content: "Hello"},{userId: 4, content: "Moi"}];
var users = [{id: 2, name: "Grace"}, {id: 4, name: "Janetta"},{id: 5, name: "Sara"}];
var messagesWithUserNames = messages.map((msg)=> {
var haveEqualId = (user) => user.id === msg.userId
var userWithEqualId= users.find(haveEqualId)
return Object.assign({}, msg, userWithEqualId)
})
console.log(messagesWithUserNames)
香草 JS 解决方案
const a1 = [{ id : 1, name : "test"}, { id : 2, name : "test2"}]
const a2 = [{ id : 1, count : "1"}, {id : 2, count : "2"}]
const merge = (arr1, arr2) => {
const temp = []
arr1.forEach(x => {
arr2.forEach(y => {
if (x.id === y.id) {
temp.push({ ...x, ...y })
}
})
})
return temp
}
console.log(merge(a1, a2))
lodash implementaiton:
var merged = _.map(a1, function(item) {
return _.assign(item, _.find(a2, ['id', item.id]));
});
结果:
[
{
"id":1,
"name":"test",
"count":"1"
},
{
"id":2,
"name":"test2",
"count":"2"
}
]
想添加这个答案,该答案源自上面的@daisihi答案。主要区别在于这使用点差运算符。另外,最后我删除了id,因为它首先是不可取的。
const a3 = [...a1, ...a2].reduce((acc, x) => {
acc[x.id] = {...acc[x.id] || {}, ...x};
return acc;
}, {});
这部分摘自另一篇文章。 从数组中的对象列表中删除属性
const newArray = Object.values(a3).map(({id, ...keepAttrs}) => keepAttrs);
发现其他解决方案在某些情况下失败,因此在这里编写更好的解决方案
const a1 = [{ id : 1, name : "test"}, { id : 2, name : "test2"}]
const a2 = [{ id : 3, count : "3"}, { id : 1, count : "1"}, {id : 2, count : "2"}]
const mergeHelper = new Map(a1.map(x => [x.id, x]));
for (const x of a2) {
if (mergeHelper.has(x.id)) {
const item = mergeHelper.get(x.id);
mergeHelper.set(x.id, {...item, ...x});
} else {
mergeHelper.set(x.id, x);
}
}
const mergedList = [...mergeHelper.values()];
// For sorted array
// const mergedSortedList = [...mergeHelper.values()].sort((a, b) => a.id - b.id);
console.log(mergedList)
使用js Map比其他方法快得多,当数组长度很大时会有所帮助。
一个有效的TypeScript版本:
export default class Merge {
static byKey(a1: any[], a2: any[], key: string) {
const res = a1.concat(a2).reduce((acc, x) => {
acc[x[key]] = Object.assign(acc[x[key]] || {}, x);
return acc;
}, {});
return Object.entries(res).map(pair => {
const [, value] = pair;
return value;
});
}
}
test("Merge", async () => {
const a1 = [{ id: "1", value: "1" }, { id: "2", value: "2" }];
const a2 = [{ id: "2", value: "3" }];
expect(Merge.byKey(a1, a2, "id")).toStrictEqual([
{
id: "1",
value: "1"
},
{ id: "2", value: "3" }
]);
});
试试这个
var a1 = [{ id : 1, name : "test"}, { id : 2, name : "test2"}]
var a2 = [{ id : 1, count : "1"}, {id : 2, count : "2"}]
let arr3 = a1.map((item, i) => Object.assign({}, item, a2[i]));
console.log(arr3);
这个怎么样?
const mergeArrayObjects = (arr1: any[], arr2: any[], mergeByKey: string): any[] => {
const updatedArr = [];
for (const obj of arr1) {
const arr1ValueInArr2 = arr2.find(
a => a[mergeByKey] === obj[mergeByKey],
);
if (arr1ValueInArr2) {
updatedArr.push(Object.assign(obj, arr1ValueInArr2));
} else {
updatedArr.push(obj);
}
}
const mergeByKeyValuesInArr1 = arr1.map(a => a[mergeByKey]);
const remainingObjInArr2 = arr2.filter(a => !mergeByKeyValuesInArr1.includes(a[mergeByKey]) )
return updatedArr.concat(remainingObjInArr2)
}
你可以像这样编写一个简单的对象合并函数
function mergeObject(cake, icing) {
var icedCake = {}, ingredient;
for (ingredient in cake)
icedCake[ingredient] = cake[ingredient];
for (ingredient in icing)
icedCake[ingredient] = icing[ingredient];
return icedCake;
}
接下来,您需要使用双循环将其应用于数据结构
var i, j, a3 = a1.slice();
for (i = 0; i < a2.length; ++i) // for each item in a2
for (j = 0; i < a3.length; ++i) // look at items in other array
if (a2[i]['id'] === a3[j]['id']) // if matching id
a3[j] = mergeObject(a3[j], a2[i]); // merge
您也可以通过将一个参数作为空对象传递mergeObject
用作简单克隆。
const a3 = a1.map(it1 => {
it1.test = a2.find(it2 => it2.id === it1.id).test
return it1
})
如果你在两个数组中具有相同数量的项目,具有相同的 id,你可以做这样的事情。
const mergedArr = arr1.map((item, i) => {
if (item.ID === arr2[i].ID) {
return Object.assign({}, item, arr2[i]);
}
});
a1.map(x => a2.find(y => y.id === x.id))
他们都不适合我。我写了自己的:
const formatteddata=data.reduce((a1,a2)=>{
for (let t=0; t<a1.length; t++)
{var id1=a1[t].id
for (let tt=0; tt<a2.length; tt++)
{var id2=a2[tt].id
if(id1==date2)
{a1[t]={...a1[t],...a2[tt]}}
}
}
return a1
})
适用于数组中任意数量的对象数组,长度不同且并不总是重合日期
- 将两个数组与对象合并
- 如何使用ES6将两个具有函数的对象合并为一个新对象
- 将值和属性从一个对象合并到另一个对象
- 如何将两个json对象合并为一个json
- 将来自多个控制器的 AngularJS 范围对象合并到一个对象中
- 在 node.js 中将 2 个 json 对象合并为一个
- Angular JS将2个对象合并为第三个对象
- JavaScript - 将两个数组对象合并为一个arr对象,然后遍历每个索引/对象
- 将同一数组中的多个对象合并为一个对象
- 如何在 Javascript 中将嵌套对象合并到它们的父对象中
- 将状态与来自循环反应的对象合并
- 将数组合并到对象以及对象合并到数组
- 如何将两个d3对象合并为一个进行批量操作
- 将JSON对象与JSON子对象合并
- 将一个对象合并到另一个对象的最佳方式(无覆盖)
- 使用jQuery扩展方法将函数与对象合并,为什么'只返回s的函数
- 如何将数组与值为数组的对象合并
- 循环遍历数组以查找具有匹配id的所有对象,并将这些对象合并到数组中的一个元素中
- Javascript将对象合并到key ->一组值
- 如何将两个查询对象合并为一个查询对象