Javascript:仅在不重复的情况下合并两个对象数组(基于指定的对象键)

时间:2019-01-10 17:40:32

标签: javascript arrays

背景

说我有一个初始的对象数组:

var initialData = [
    {
        'ID': 1,
        'FirstName': 'Sally'
    },
    {
        'ID': 2,
        'FirstName': 'Jim'
    },
    {
        'ID': 3,
        'FirstName': 'Bob'
    }
];

然后我获取新数据(另一组对象):

var newData = [
    {
        'ID': 2,
        'FirstName': 'Jim'
    },
    {
        'ID': 4,
        'FirstName': 'Tom'
    },
    {
        'ID': 5,
        'FirstName': 'George'
    }
];

目标

我想将新数据合并为初始数据。但是,我不想覆盖初始数据数组中的任何对象。我只想添加尚不存在的对象。

我知道这些对象是根据其'ID'键来复制的。

我尝试过的

我知道我可以通过遍历新数据,检查是否在初始数据中存在,如果不存在,则推入初始数据来做到这一点。

for ( var i = 0, l = newData.length; i < l; i++  ) {

    if ( ! key_exists( newData[i].key, initialData ) ) {  // key_exists() is a function that uses .filter() to test.

        initialData.push( newData[i] );

    }


}

不过,我担心性能。我知道有很多新的ES6处理数组的方式,所以我希望有人有更好的主意。

问题

在忽略新数据重复项的同时,将新数据合并到初始数据中的最佳方法是什么(最好与最佳性能一样)?

3 个答案:

答案 0 :(得分:4)

您可以从initialData创建一组ID,这样可以更快地“检查ID是否已包含在初始数据中”-O(1):

var initialData = [{
    'ID': 1,
    'FirstName': 'Sally'
  },
  {
    'ID': 2,
    'FirstName': 'Jim'
  },
  {
    'ID': 3,
    'FirstName': 'Bob'
  }
];

var newData = [{
    'ID': 2,
    'FirstName': 'Jim'
  },
  {
    'ID': 4,
    'FirstName': 'Tom'
  },
  {
    'ID': 5,
    'FirstName': 'George'
  }
];

var ids = new Set(initialData.map(d => d.ID));
var merged = [...initialData, ...newData.filter(d => !ids.has(d.ID))];

console.log(merged);

此方法的最终运行时间为 O(n + m)

如果您想提高效率,可以考虑遍历newData并将任何新元素手动推送到最终结果数组中(而不是使用filter和散布运算符)。

答案 1 :(得分:1)

实际上,如果您对性能感兴趣,可以考虑将initialData结构更改为以下形式:

var initialData = {
    "1": {'FirstName': 'Sally'},
    "2": {'FirstName': 'Jim'},
    "3": {'FirstName': 'Bob'}
};

换句话说,我们将ID用作对象的键,这将使您O(1)可以访问数据,而O(1)可以用于存在测试。您可以使用带有reduce()的下一种方法来获得此结构:

var initialData = [
    {'ID': 1, 'FirstName': 'Sally'},
    {'ID': 2, 'FirstName': 'Jim'},
    {'ID': 3, 'FirstName': 'Bob'}
];

let newInitialData = initialData.reduce((res, {ID, FirstName}) =>
{
    res[ID] = {FirstName : FirstName};
    return res;
}, {});

console.log(newInitialData);

使用这种新结构,您可以使用O(n)算法来插入尚不存在的新数据:

var initialData = {
    "1": {'FirstName': 'Sally'},
    "2": {'FirstName': 'Jim'},
    "3": {'FirstName': 'Bob'}
};

var newData = [
    {'ID': 2, 'FirstName': 'Jim'},
    {'ID': 4, 'FirstName': 'Tom'},
    {'ID': 5, 'FirstName': 'George'}
];

newData.forEach(({ID, FirstName}) =>
{
    initialData[ID] = initialData[ID] || {FirstName: FirstName};
});

console.log(initialData);

答案 2 :(得分:0)

我认为@slider在接受的答案中提出的替代解决方案是这样的:

#include<cstdio>

void print(const char** x){
    printf("%s", x[0]);
}

int main(int argc, char **argv){
    if(argc>1){
        print((const char **)argv);     
    }
     return 0;
}

//Then compile it as follow:

$ g++ -Wcast-qual test.cpp

//gives the following output:

MCVE.cpp: In function ‘int main(int, char**)’:
MCVE.cpp:5:36: warning: cast from type ‘char**’ to type ‘const char**’ casts away qualifiers [-Wcast-qual]
   const char ** q = (const char**) argv;