替换数组中的对象

问题描述 投票:0回答:18

我有这个javascript对象:

var arr1 = [{id:'124',name:'qqq'}, 
           {id:'589',name:'www'}, 
           {id:'45',name:'eee'},
           {id:'567',name:'rrr'}]

var arr2 = [{id:'124',name:'ttt'}, 
           {id:'45',name:'yyy'}]

我需要将 arr1 中的对象替换为 arr2 中具有相同 id 的项目。

所以这是我想要得到的结果:

var arr1 = [{id:'124',name:'ttt'}, 
           {id:'589',name:'www'}, 
           {id:'45',name:'yyy'},
           {id:'567',name:'rrr'}]

如何使用javascript实现它?

javascript lodash
18个回答
281
投票

您可以将

Array#map
Array#find
一起使用。

arr1.map(obj => arr2.find(o => o.id === obj.id) || obj);

var arr1 = [{
    id: '124',
    name: 'qqq'
}, {
    id: '589',
    name: 'www'
}, {
    id: '45',
    name: 'eee'
}, {
    id: '567',
    name: 'rrr'
}];

var arr2 = [{
    id: '124',
    name: 'ttt'
}, {
    id: '45',
    name: 'yyy'
}];

var res = arr1.map(obj => arr2.find(o => o.id === obj.id) || obj);

console.log(res);

这里,如果在

arr2.find(o => o.id === obj.id)
中找到
arr2
id
将返回来自
arr2
的元素,即对象。如果不是,则返回
arr1
中的相同元素,即
obj


10
投票

关于时间与空间总是会有一场很好的争论,但是这些天我发现从长远来看使用空间更好。抛开数学不谈,让我们看一下使用散列图、字典或关联数组是您想要标记的任何简单数据结构..

    var marr2 = new Map(arr2.map(e => [e.id, e]));
    arr1.map(obj => marr2.has(obj.id) ? marr2.get(obj.id) : obj);

我喜欢这种方法,因为尽管您可能会与数字较小的数组争论,但您却在浪费空间,因为像 @Tushar 方法这样的内联方法的性能与此方法几乎没有区别。不过,我运行了一些测试,图表显示了两种方法在 n 0 - 1000 范围内的性能(以毫秒为单位)。您可以根据您的情况决定哪种方法最适合您,但根据我的经验,用户不太关心小空间,但他们确实关心小速度。



这是我为数据源运行的性能测试

var n = 1000;
var graph = new Array();
for( var x = 0; x < n; x++){
  var arr1s = [...Array(x).keys()];
  var arr2s = arr1s.filter( e => Math.random() > .5);
  var arr1 = arr1s.map(e => {return {id: e, name: 'bill'}});
  var arr2 = arr2s.map(e => {return {id: e, name: 'larry'}});
  // Map 1
  performance.mark('p1s');
  var marr2 = new Map(arr2.map(e => [e.id, e]));
  arr1.map(obj => marr2.has(obj.id) ? marr2.get(obj.id) : obj);
  performance.mark('p1e');
  // Map 2
  performance.mark('p2s');
  arr1.map(obj => arr2.find(o => o.id === obj.id) || obj);
  performance.mark('p2e');
  graph.push({ x: x, r1: performance.measure('HashMap Method', 'p1s', 'p1e').duration, r2: performance.measure('Inner Find', 'p2s','p2e').duration});
}

9
投票

有什么问题

Object.assign(target, source)

数组在Javascript中仍然是类型对象,因此只要找到匹配的键,使用分配仍然应该重新分配由运算符解析的任何匹配的键,对吗?


8
投票

我想建议另一种解决方案:

const objectToReplace = this.array.find(arrayItem => arrayItem.id === requiredItem.id);
Object.assign(objectToReplace, newObject);

5
投票

由于您使用的是 Lodash,您可以使用

_.map
_.find
来确保支持主要浏览器。

最后我会选择这样的东西:

function mergeById(arr) {
  return {
    with: function(arr2) {
      return _.map(arr, item => {
        return _.find(arr2, obj => obj.id === item.id) || item
      })
    }
  }
}

var result = mergeById([{id:'124',name:'qqq'}, 
           {id:'589',name:'www'}, 
           {id:'45',name:'eee'},
           {id:'567',name:'rrr'}])
    .with([{id:'124',name:'ttt'}, {id:'45',name:'yyy'}])

console.log(result);
<script src="https://raw.githubusercontent.com/lodash/lodash/4.13.1/dist/lodash.js"></script>


5
投票

我喜欢用

arr2
遍历
foreach()
并使用
findIndex()
检查
arr1
中是否出现:

var arr1 = [{id:'124',name:'qqq'}, 
           {id:'589',name:'www'}, 
           {id:'45',name:'eee'},
           {id:'567',name:'rrr'}]

var arr2 = [{id:'124',name:'ttt'}, 
           {id:'45',name:'yyy'}]

arr2.forEach(element => {
            const itemIndex = arr1.findIndex(o => o.id === element.id);
            if(itemIndex > -1) {
                arr1[itemIndex] = element;
            } else {
                arr1 = arr1.push(element);
            }       
        });
    
console.log(arr1)


4
投票

感谢 ES6,我们可以用简单的方法实现它 -> 例如在 util.js 模块上 ;)))。

  1. 合并2个实体数组

    export const mergeArrays = (arr1, arr2) => 
       arr1 && arr1.map(obj => arr2 && arr2.find(p => p.id === obj.id) || obj);
    

获取 2 个数组并将其合并.. Arr1 是主数组,优先级是 高合并过程

  1. 将数组与相同类型的实体合并

    export const mergeArrayWithObject = (arr, obj) => arr && arr.map(t => t.id === obj.id ? obj : t);
    

它将相同类型的数组与某种类型合并为

示例:人员数组 ->

[{id:1, name:"Bir"},{id:2, name: "Iki"},{id:3, name:"Uc"}]   
second param Person {id:3, name: "Name changed"}   

结果是

[{id:1, name:"Bir"},{id:2, name: "Iki"},{id:3, name:"Name changed"}]

3
投票

考虑到接受的答案对于大型数组 O(nm) 可能效率较低,我通常更喜欢这种方法,O(2n + 2m):

function mergeArrays(arr1 = [], arr2 = []){
    //Creates an object map of id to object in arr1
    const arr1Map = arr1.reduce((acc, o) => {
        acc[o.id] = o;
        return acc;
    }, {});
    //Updates the object with corresponding id in arr1Map from arr2, 
    //creates a new object if none exists (upsert)
    arr2.forEach(o => {
        arr1Map[o.id] = o;
    });

    //Return the merged values in arr1Map as an array
    return Object.values(arr1Map);
}

单元测试:

it('Merges two arrays using id as the key', () => {
   var arr1 = [{id:'124',name:'qqq'}, {id:'589',name:'www'}, {id:'45',name:'eee'}, {id:'567',name:'rrr'}];
   var arr2 = [{id:'124',name:'ttt'}, {id:'45',name:'yyy'}];
   const actual = mergeArrays(arr1, arr2);
   const expected = [{id:'124',name:'ttt'}, {id:'589',name:'www'}, {id:'45',name:'yyy'}, {id:'567',name:'rrr'}];
   expect(actual.sort((a, b) => (a.id < b.id)? -1: 1)).toEqual(expected.sort((a, b) => (a.id < b.id)? -1: 1));
})

2
投票
// here find all the items that are not it the arr1
const temp = arr1.filter(obj1 => !arr2.some(obj2 => obj1.id === obj2.id))
// then just concat it
arr1 = [...temp, ...arr2]

2
投票

这是一种更透明的方法。我发现单行代码更难阅读,也更难调试。

export class List {
    static replace = (object, list) => {
        let newList = [];
        list.forEach(function (item) {
            if (item.id === object.id) {
                newList.push(object);
            } else {
                newList.push(item);
            }
        });
        return newList;
    }
}

0
投票

如果您不关心数组的顺序,那么您可能想使用

differenceBy()
获得
arr1
arr2
之间的差异,然后只需使用 concat() 即可追加所有更新的对象。 id

var result = _(arr1).differenceBy(arr2, 'id').concat(arr2).value();
var arr1 = [{
  id: '124',
  name: 'qqq'
}, {
  id: '589',
  name: 'www'
}, {
  id: '45',
  name: 'eee'
}, {
  id: '567',
  name: 'rrr'
}]

var arr2 = [{
  id: '124',
  name: 'ttt'
}, {
  id: '45',
  name: 'yyy'
}];

var result = _(arr1).differenceBy(arr2, 'id').concat(arr2).value();

console.log(result);


0
投票

话虽如此,为了便于阅读,我将问题分解为两个函数。

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js"></script>

jsfiddle


0
投票


0
投票

function getMatch(elem) { function action(ele, val) { if(ele === val){ elem = arr2[i]; } } for (var i = 0; i < arr2.length; i++) { action(elem.id, Object.values(arr2[i])[0]); } return elem; } var modified = arr1.map(getMatch);



0
投票

masterData = [{id: 1, name: "aaaaaaaaaaa"}, {id: 2, name: "Bill"}, {id: 3, name: "ccccccccc"}]; updatedData = [{id: 3, name: "Cat"}, {id: 1, name: "Apple"}]; updatedData.forEach(updatedObj=> { // For every updatedData object (dataObj), find the array index in masterData where the IDs match. let indexInMasterData = masterData.map(masterDataObj => masterDataObj.id).indexOf(updatedObj.id); // First make an array of IDs, to use indexOf(). // If there is a matching ID (and thus an index), replace the existing object in masterData with the updatedData's object. if (indexInMasterData !== undefined) masterData.splice(indexInMasterData, 1, updatedObj); }); /* masterData becomes [{id: 1, name: "Apple"}, {id: 2, name: "Bill"}, {id: 3, name: "Cat"}]; as you want.`*/



0
投票

//newArr contains the mapped array from arr2 to arr1. //arr1 still contains original value var newArr = arr1.map(obj => arr2.find(o => o.id === obj.id) || obj);


0
投票
使用 key 合并和更新记录的高效 JavaScript 代码

论坛上已经有一些很好的答案,但我仍在发布我在 JavaScript 中合并和更新记录的改进解决方案。

Array.prototype.update = function(...args) { return this.map(x=>args.find((c)=>{return c.id===x.id}) || x) } const result = [ {id:'1',name:'test1'}, {id:'2',name:'test2'}, {id:'3',name:'test3'}, {id:'4',name:'test4'} ] .update({id:'1',name:'test1.1'}, {id:'3',name:'test3.3'}) console.log(result)


-3
投票

const existingItems = [ { id: 1, name: 'Item A', category: 'Category 1' }, { id: 2, name: 'Item B', category: 'Category 2' }, { id: 3, name: 'Item C', category: 'Category 1' }, // Add more source items as needed ]; // Usually new data from the server const newItems = [ { id: 3, name: 'Item C', category: 'Category 3' }, { id: 4, name: 'Item D', category: 'Category 4' }, // Add more new items as needed ]; let key = "id"; let newList = [...new Map([...existingItems, ...newItems].map((item) => [item[key], item])).values()]; console.log(newList);

© www.soinside.com 2019 - 2024. All rights reserved.