【问题标题】:How can I create a merged object from an array of objects that preserves properties in the original object not changed from the new incoming object如何从对象数组创建合并对象,该对象数组保留原始对象中的属性,而不是从新传入对象更改
【发布时间】:2019-09-01 10:59:27
【问题描述】:

我必须对象/数组集...

var test = [{id: 1, prop: 'bill', location: 'san diego'},{id: 11, prop: 'bright'}];
var test2 = [{id: 1, prop: 'casey'},{id: 11, prop: 'candle'}];

最终,我希望 test2 中的对象更改 test 中的属性,但保留原始对象中的 location 属性,因为它没有更改甚至在 test2 中引用。

我所做的是设置一个映射,该映射的键是 id,并使用每个对象作为值。

问题是每个键的新对象的值将完全覆盖以前的原始对象。因此, location 属性会从原始数组中删除。

特别是从 Object.assign() 中,未作为对象数组呈现的裸对象将保持原始对象的完整性,并且只会更改底层属性。

以下是两者的示例:

对象数组:

var o1 = [{id: 1, prop: 'bill', location: 'san diego'},{id: 11, prop: 'bright'}];
var o2 = [{id: 1, prop: 'casey'},{id: 11, prop: 'candle'}];
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // 0: {id: 1, prop: "casey"} 1: {id: 11, prop: "candle"} c: 3

单一对象:

var o1 = {id: 1, prop: 'bill', location: 'san diego'};
var o2 = {id: 1, prop: 'casey'};
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // {id: 1, prop: "casey", location: "san diego", c: 3}

以单一格式处理对象具有预期的效果,因此答案可能就在这个事实中。是否有一种简洁的方法来执行此操作,或者是否需要以循环方式构建,一次处理一条记录?如果是这样,这将是一个什么例子?

这是我正在处理的映射代码:

var test = [{id: 1, prop: 'bill', location: 'san diego'},{id: 11, prop: 'bright'}];
var first = new Map();
for (const value of test) {
    //console.log(key + ' = ' + value.id);
    first.set(value.id, value);
    //console.log(first);
}
var test2 = [{id: 1, prop: 'casey'},{id: 11, prop: 'candle'}];
var second = new Map();
for (const value of test2) {
    second.set(value.id, value);
}

var merged = new Map([...first, ...second]);

let mergedArray = [];
for (var value of merged.values()) {
  console.log(' = ' + value);
    mergedArray.push(value);
}

console.log('merged', mergedArray);
// console.log(merged)

// console.log('second2', second);
// console.log('first2 ', first);

【问题讨论】:

  • 应用 KISS 原则。

标签: javascript arrays mapping javascript-objects


【解决方案1】:
const merged = test.map(ele => {
  const found = test2.find(({id}) => id === ele.id) || {}
  return {...ele, ...found}
})
  • 循环遍历test
  • test2 中找到相同的 id 元素(如果没有找到,则设置一个空对象)
  • 返回合并的对象,其中test 是源,test2 包含覆盖/添加

【讨论】:

  • 好吧,所以我认为我做错了......基本上这是同一件事,除了我的每个地图 id 都是一个值,所以当它在合并时合并整个值时被替换.. .但是我需要每个对象来替换你所做的属性。有趣。
  • 如果我的解决方案是您正在寻找的解决方案,请将其标记为已接受或寻求进一步帮助
  • 即使test2 的成员在test 中不存在,也可以对其进行编辑
【解决方案2】:

试试这样的。

const test = [{
    id: 1,
    prop: 'bill',
    location: 'san diego'
  }, {
    id: 11,
    prop: 'bright'
  }, {
    id: 12, //not in test2
    prop: 'something',
    location: 'NY'
  },
  {
    id: 13, //no "prop" in test2
    prop: 'something',
    location: 'NY'
  }
];
const test2 = [{
    id: 1,
    prop: 'casey'
  }, {
    id: '11',
    prop: 'candle'
  },
  {
    id: 13,
    something: false
  },
  {
    id: 100, // not in test
    prop: 'other'
  }
];
test.forEach(t => {
  const t2 = test2.find(t2 => t2.id == t.id);//=== for exact match
  if (t2)
    t.prop = t2.prop || t.prop;
});
console.log(test);

【讨论】:

  • 使用双等号 == 是个坏主意,字符串和数字 id 将无法区分并合并
  • @Marcin 这是有目的的。在这种情况下,它们应该是无法区分的。
  • 这不是。对于未从传入对象复制的属性,初始对象的完整性必须保持不变
  • 我也想弄清楚为什么这还不够。您的解决方案取决于与您要查找的属性相匹配的语句。而上述匹配整个对象。传入的内容必须覆盖它是少还是多。如果没有匹配的覆盖属性,则不能覆盖什么。而且上面的解决方案更容易阅读,尤其是你之前建议的 KISS 原则
  • 从 sn-p 中可以看出,test 已更新iff id 匹配(松散的== 或精确的=== 属性 (prop) 存在于test2
【解决方案3】:

使用 Map() 函数提供此答案,以便可以首先将对象设置为键值。接受的答案简短明了,但这可能有额外的价值。

var test = [{id: 1, prop: 'bill', location: 'san diego'},{id: 11, prop: 'bright'}];
  var test2 = [{id: 1, prop: 'casey'},{id: 11, prop: 'candle'}];

  const map = new Map(test.map(obj => [obj.id, obj]));
  for (const item of test2) {
    if (map.has(item.id)) {
      // map.set( item.id, item ); // replace the item value
      map.set(item.id, { ...map.get(item.id),
        ...item
      }); 
    }
  }
  console.log(Array.from(map));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-08
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    相关资源
    最近更新 更多