【问题标题】:Javascript arrays and objects: Get differences and merge themJavascript 数组和对象:获取差异并合并它们
【发布时间】:2018-03-31 14:19:15
【问题描述】:

所以我有这种情况,我有一个 client-app 将数据(对象数组)发送到 server,然后将数据转发到 other客户端 连接到此服务器。

client-app中,数据是不断变化的,意思是:数值变化,数组里面的新对象弹出,对象被移除等等……

现在我希望其他客户始终收到最新数据。而且因为我不希望 client-app 只是将 全新数据 推送到服务器,然后服务器将 全新数据 转发到 其他客户端,我决定让client-app 只推送更改(使用这个库:https://www.npmjs.com/package/deep-object-diff)。

其他客户端然后收到一个对象数组,其中只有实际更改的数据,因为他们知道以前的数据数组,我希望他们“合并”旧数据对象的更改数组。

我的实际问题是合并。我不知道如何正确地做到这一点。特别是如果我有一个没有任何对象键的对象数组。

所以我的数据看起来像这样:

let data = [
  {
    name: 'Peter',
    age: 26,
    sID: 546589995544
  },
  {
    name: 'John',
    age: 33,
    sID: 554589525469
  }
];

其实还有很多,不过就是这样的结构。

所以如果 diff 库说,这就是变化:

let changes = {
  {
    age: 34,
    sID: 554589525469
  }
};

(请注意,我现在有一个对象对象,而不是对象数组。这就是差异库返回的内容)

我希望合并的对象是

[
  {
    name: 'Peter',
    age: 26,
    sID: 546589995544
  },
  {
    name: 'John',
    age: 34,
    sID: 554589525469
  }
];

(约翰现在大了一岁)

所以我完全相信,如果我有一个对象的键作为标识符,这会容易得多,但我仍然认为必须有一个解决方案来解决这种情况。如您所见,sID 属性可以充当标识符,但它不是键。

如果有人能指出在这两种情况下如何做(有和没有对象的特定键),我会很感激

【问题讨论】:

标签: javascript arrays merge javascript-objects array-difference


【解决方案1】:

如果您的更改数据是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);

【讨论】:

  • 感谢您的回答。工作至今。你能告诉我如果我有一个对象的对象,每个对象都有一个键,而不仅仅是一个具有唯一标识符的新字段,它会如何工作吗?
  • 我认为你可以使用 Object.keys ,这将检索对象键作为数组列表..
【解决方案2】:

使用lodash,您可以使用unionBy 完成此操作:

const newData = _.unionBy(changes, data, 'sID'); // values from changes will be picked

这将根据sID 从两个数组中挑选对象并将它们组合成一个数组。

【讨论】:

  • 工作,直到一个新对象被添加到初始数据中。
  • @SVARTBERG 添加新对象时,再次运行 unionBy。
【解决方案3】:

您可以使用.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);

【讨论】:

  • 似乎是一个不错的方法,有点效果。它只是对我不起作用,因为差异库不返回对象数组,而是返回以对象为成员的对象。然后,您的解决方案不再起作用,因为 changes[Symbol.iterator] 不是函数。有什么解决办法吗?
  • 您可以使用Object.values()Object.entries() 将对象转换为属性、值对数组的数组。为什么你没有在问题的代码中包含实际使用的对象?
  • 我的错,对不起。写问题的时候没有考虑。所以你认为我应该再次将更改转换为对象数组?我必须研究如何使用您建议的功能来实现这一目标。谢谢。
【解决方案4】:

您可以使用 sId Map 进行快速查找:

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);
 }
});

【讨论】:

  • 你的数据是什么?和guest271314答案的评论中的问题一样
  • 哦,对不起,没有得到您的代码覆盖旧数据对象的事实。感谢到目前为止。还要做一些测试
猜你喜欢
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 2014-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-18
  • 1970-01-01
相关资源
最近更新 更多