替换数组中的对象

时间:2016-06-02 07:27:58

标签: javascript lodash

我有这个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实现它?

14 个答案:

答案 0 :(得分:50)

您可以将Array#mapArray#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

答案 1 :(得分:3)

关于时间与空间的争论总是会发生,但是现在我发现从长远来看,使用空间更好.. 撇开数学不谈,让我们看看使用哈希图、字典解决问题的一种实用方法,或关联数组的任何你觉得标记简单的数据结构..

    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 之间的性能如何。您可以根据自己的情况决定哪种方法最适合您,但根据我的经验,用户不太关心小空间,但是他们确实关心小速度。


Performance Measurement


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

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

答案 2 :(得分: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;
    }
}

答案 3 :(得分: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]

答案 4 :(得分:1)

由于您使用的是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 :(得分:1)

如果您不关心数组的顺序,那么您可能希望arr1使用differenceBy() arr2之间区分idvar result = _(arr1).differenceBy(arr2, 'id').concat(arr2).value(); 然后只需使用concat()附加所有更新的对象。

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

&#13;
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js"></script>
&#13;
SELECT u.id, u.name, u.function_id,      
       GROUP_CONCAT(f.function) AS function_name
FROM Users AS u
LEFT JOIN Function AS f ON FIND_IN_SET(f.id, u.function_id) > 0
GROUP BY u.id, u.name
&#13;
&#13;
&#13;

答案 6 :(得分:1)

我只是提交这个答案,因为人们对浏览器表示担忧并维护对象的顺序。我认识到这不是实现目标的最有效方式。

话虽如此,我将问题分解为两个功能以便于阅读。

// The following function is used for each itertion in the function updateObjectsInArr
const newObjInInitialArr = function(initialArr, newObject) {
  let id = newObject.id;
  let newArr = [];
  for (let i = 0; i < initialArr.length; i++) {
    if (id === initialArr[i].id) {
      newArr.push(newObject);
    } else {
      newArr.push(initialArr[i]);
    }
  }
  return newArr;
};

const updateObjectsInArr = function(initialArr, newArr) {
    let finalUpdatedArr = initialArr;  
    for (let i = 0; i < newArr.length; i++) {
      finalUpdatedArr = newObjInInitialArr(finalUpdatedArr, newArr[i]);
    }

    return finalUpdatedArr
}

const revisedArr = updateObjectsInArr(arr1, arr2);

jsfiddle

答案 7 :(得分:1)

Object.assign(target, source)怎么了?

enter image description here

数组仍然是Javascript中的类型对象,因此只要找到匹配键,使用分配就应该仍然重新分配操作员解析的所有匹配键,对吧?

答案 8 :(得分:1)

考虑到公认的答案对于大型阵列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));
})

答案 9 :(得分:0)

感谢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”}]第二个参数Person {id:3,name:“ Name   已更改”}的结果是[{id:1,name:“ Bir”},{id:2,name:“ Iki”},{id:3,   名称:“名称已更改”}]

答案 10 :(得分: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);

答案 11 :(得分: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.`*/

答案 12 :(得分:0)

使用 array.map 的公认答案是正确的,但您必须记住将其分配给另一个变量,因为 array.map 不会更改原始数组,它实际上会创建一个新数组。

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

答案 13 :(得分:-1)

这是我在TypeScript中执行的操作:

const index = this.array.indexOf(this.objectToReplace);
this.array[index] = newObject;