Javascript 数组和对象:获取差异并合并它们
Javascript arrays and objects: Get differences and merge them
所以我有这样一个场景,我有一个 client-app 将数据(对象数组)发送到 server 然后将数据转发给连接到此服务器的其他客户端。
在client-app中,数据是不断变化的,意思是:数值变化,数组里面的新对象弹出,对象被移除,等等...
现在我希望 其他客户端 始终接收最新数据。而且因为我不希望 client-app 将 全新数据 推送到服务器,然后服务器转发 全新数据data 到 other clients,我决定让 client-app 只推送 changes(使用这个库:https://www.npmjs.com/package/deep-object-diff)。
其他客户端然后收到一个对象数组,其中只有实际更改的数据,因为他们知道以前的数据数组, 我希望他们 "merge" 更改数组与旧数据对象。
我的实际问题是合并。我不知道如何正确地做到这一点。特别是如果我有一个没有任何对象键的对象数组。
所以我的数据看起来像这样:
let data = [
{
name: 'Peter',
age: 26,
sID: 546589995544
},
{
name: 'John',
age: 33,
sID: 554589525469
}
];
实际上还有很多,不过,这就是结构。
因此,如果 diff 库说,这就是更改:
let changes = {
{
age: 34,
sID: 554589525469
}
};
(注意我现在有一个对象的对象,而不是一个对象数组。这就是 diff-library returns)
我希望合并后的对象是
[
{
name: 'Peter',
age: 26,
sID: 546589995544
},
{
name: 'John',
age: 34,
sID: 554589525469
}
];
(约翰现在大了一岁)
所以我完全相信,如果我有一个对象的键作为标识符,这会容易得多,但我仍然认为必须有一个解决方案来解决这个问题。如您所见,sID 属性 可以充当标识符,它只是不是键。
如果有人能指出在这两种情况下如何做到这一点(有和没有对象的特定键),我将不胜感激
您可以使用 sId 映射进行快速查找:
const byId = new Map( data.map( el => [el.sID, el]));
然后对于每个更改,我们可以找到 obj 是否已经存在,如果不存在我们添加它,如果是我们变异:
changes.forEach(change => {
const res = byId.get( change.sID );
if( res ){
Object.assign( res, change);
}else{
data.push(change);
byId.set( change.sID, change);
}
});
您可以使用 .find()
查找数组中应更改值的对象,Object.assign()
设置值
let data = [{
name: 'Peter',
age: 26,
sID: 546589995544
},
{
name: 'John',
age: 33,
sID: 554589525469
}
];
let changes = [{
age: 34,
sID: 554589525469
}];
for (let prop of changes) {
let {sID} = prop;
Object.assign(data.find(({sID: id}) => id === sID), prop)
}
console.log(data);
使用lodash, you can accomplish this with unionBy:
const newData = _.unionBy(changes, data, 'sID'); // values from changes will be picked
这将根据sID
从两个数组中选取对象并将它们组合成一个数组。
如果你更改的数据是 object of objects
,你可以使用 Object.values
循环数据值并通过 Object.assign
合并相同的 id 数据
let data = [
{
name: 'Peter',
age: 26,
sID: 546589995544
},
{
name: 'John',
age: 33,
sID: 554589525469
}
];
let changes = {
0:
{
age: 34,
sID: 554589525469
}
};
data.filter((idx,i)=>
Object.values(changes).forEach((index)=>
(index.sID == idx.sID) ? Object.assign(data[i],index) : null
)
);
console.log(data);
所以我有这样一个场景,我有一个 client-app 将数据(对象数组)发送到 server 然后将数据转发给连接到此服务器的其他客户端。
在client-app中,数据是不断变化的,意思是:数值变化,数组里面的新对象弹出,对象被移除,等等...
现在我希望 其他客户端 始终接收最新数据。而且因为我不希望 client-app 将 全新数据 推送到服务器,然后服务器转发 全新数据data 到 other clients,我决定让 client-app 只推送 changes(使用这个库:https://www.npmjs.com/package/deep-object-diff)。
其他客户端然后收到一个对象数组,其中只有实际更改的数据,因为他们知道以前的数据数组, 我希望他们 "merge" 更改数组与旧数据对象。
我的实际问题是合并。我不知道如何正确地做到这一点。特别是如果我有一个没有任何对象键的对象数组。
所以我的数据看起来像这样:
let data = [
{
name: 'Peter',
age: 26,
sID: 546589995544
},
{
name: 'John',
age: 33,
sID: 554589525469
}
];
实际上还有很多,不过,这就是结构。
因此,如果 diff 库说,这就是更改:
let changes = {
{
age: 34,
sID: 554589525469
}
};
(注意我现在有一个对象的对象,而不是一个对象数组。这就是 diff-library returns)
我希望合并后的对象是
[
{
name: 'Peter',
age: 26,
sID: 546589995544
},
{
name: 'John',
age: 34,
sID: 554589525469
}
];
(约翰现在大了一岁)
所以我完全相信,如果我有一个对象的键作为标识符,这会容易得多,但我仍然认为必须有一个解决方案来解决这个问题。如您所见,sID 属性 可以充当标识符,它只是不是键。
如果有人能指出在这两种情况下如何做到这一点(有和没有对象的特定键),我将不胜感激
您可以使用 sId 映射进行快速查找:
const byId = new Map( data.map( el => [el.sID, el]));
然后对于每个更改,我们可以找到 obj 是否已经存在,如果不存在我们添加它,如果是我们变异:
changes.forEach(change => {
const res = byId.get( change.sID );
if( res ){
Object.assign( res, change);
}else{
data.push(change);
byId.set( change.sID, change);
}
});
您可以使用 .find()
查找数组中应更改值的对象,Object.assign()
设置值
let data = [{
name: 'Peter',
age: 26,
sID: 546589995544
},
{
name: 'John',
age: 33,
sID: 554589525469
}
];
let changes = [{
age: 34,
sID: 554589525469
}];
for (let prop of changes) {
let {sID} = prop;
Object.assign(data.find(({sID: id}) => id === sID), prop)
}
console.log(data);
使用lodash, you can accomplish this with unionBy:
const newData = _.unionBy(changes, data, 'sID'); // values from changes will be picked
这将根据sID
从两个数组中选取对象并将它们组合成一个数组。
如果你更改的数据是 object of objects
,你可以使用 Object.values
循环数据值并通过 Object.assign
let data = [
{
name: 'Peter',
age: 26,
sID: 546589995544
},
{
name: 'John',
age: 33,
sID: 554589525469
}
];
let changes = {
0:
{
age: 34,
sID: 554589525469
}
};
data.filter((idx,i)=>
Object.values(changes).forEach((index)=>
(index.sID == idx.sID) ? Object.assign(data[i],index) : null
)
);
console.log(data);