比较两个对象数组,并排除在JS中将值匹配到新数组的元素

时间:2021-07-29 12:18:37

here is my use case in JavaScript:

以下是我在JavaScript中的用例:

I have two arrays of objects which have properties that match (id & name).

我有两个具有匹配属性的对象数组(id & name)。

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'johnny@example.com'},
    {id:4, name:'Bobby', email:'bobby@example.com'}
];

var props = ['id', 'name'];

My goal is to have another array of objects containing only the elements which did not match. Like this:

我的目标是拥有另一个对象数组,其中只包含不匹配的元素。是这样的:

var result = [
    {id:1, name:'Sandra'},
    {id:3, name:'Peter'}
];

I know that there is a way of doing this by going from result1 compare each object with the objects of result2, then compare their keys, and if did'n match, put the values in another object then push it in new array, but I wonder is there any more elegant way, like using lo-dash or underscore or something similar.

我知道有一种方法通过从result2 result1比较每个对象和对象编写此表达式,然后比较他们的钥匙,如果是重要的比赛,把另一个对象中的值然后把它在新数组,但我不知道有什么更优雅的方式,如使用lo-dash或下划线或类似的东西。

Thank you!

谢谢你!

6 个解决方案

#1


28  

Just using the Array iteration methods built into JS is fine for this:

仅仅使用构建在JS中的数组迭代方法就可以做到这一点:

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'johnny@example.com'},
    {id:4, name:'Bobby', email:'bobby@example.com'}
];

var props = ['id', 'name'];

var result = result1.filter(function(o1){
    // filter out (!) items in result2
    return !result2.some(function(o2){
        return o1.id === o2.id;          // assumes unique id
    });
}).map(function(o){
    // use reduce to make objects with only the required properties
    // and map to apply this to the filtered array as a whole
    return props.reduce(function(newo, name){
        newo[name] = o[name];
        return newo;
    }, {});
});

document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 4) +
        '</pre>';

If you are doing this a lot, then by all means look at external libraries to help you out, but it's worth learning the basics first, and the basics will serve you well here.

如果您经常这样做,那么请务必查看外部库以帮助您解决问题,但是首先值得学习基础知识,基础知识将在这里很好地为您服务。

#2


9  

The same result can be achieved using Lodash.

使用Lodash也可以达到相同的结果。

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'johnny@example.com'},
    {id:4, name:'Bobby', email:'bobby@example.com'}
];

var result3 = _(result1) 
        .differenceBy(result2, 'id', 'name')
        .map(_.partial(_.pick, _, 'id', 'name'))
        .value();

console.log(result3);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>

You can get the desired result applying a difference between both arrays using the properties "id" and "name" as a way to "link" elements between them. If any of those properties are different, the elements are considered different (improbably in your case because id seems to be unique).

您可以使用属性“id”和“name”在两个数组之间应用一个差异,作为在它们之间“链接”元素的一种方式,获得所需的结果。如果这些属性中有任何一个是不同的,那么元素就会被认为是不同的(在您的例子中,可能是不同的,因为id似乎是唯一的)。

Lastly, you have to map the result in order to "omit" the undesired properties of the object.

最后,您必须映射结果,以便“忽略”对象的不希望的属性。

Hope it helps.

希望它可以帮助。

#3


7  

well, this using lodash or vanilla javascript it depends on the situation.

这个使用lodash或vanilla javascript取决于情况。

but for just return the array that contains the duplicates it can be achieved by the following, offcourse it was taken from @1983

但是仅仅返回包含重复的数组,它就可以通过以下方法实现,当然它是从@1983获得的

var result = result1.filter(function (o1) {
    return result2.some(function (o2) {
        return o1.id === o2.id; // return the ones with equal id
   });
});
// if you want to be more clever...
let result = result1.filter(o1 => result2.some(o2 => o1.id === o2.id));

#4


4  

I have searched a lot for a solution in which I can compare two array of objects with different attribute names (something like a left outer join). I came up with this solution. Here I used Lodash. I hope this will help you.

我已经寻找了很多解决方案,在其中我可以比较具有不同属性名称的两个对象数组(类似于左外连接)。我想到了这个解决方案。在这里我用Lodash。我希望这能对你有所帮助。

var Obj1 = [
    {id:1, name:'Sandra'},
    {id:2, name:'John'},   
];

var Obj2 = [
    {_id:2, name:'John'},
    {_id:4, name:'Bobby'}
];

var Obj3 = lodash.differenceWith(Obj1, Obj2, function (o1, o2) {
    return o1['id'] === o2['_id']
});

console.log(Obj3);
//  {id:1, name:'Sandra'}

#5


2  

Check out difference and xor in lodash.

在lodash中检查差异和xor。

#6


0  

Here is another solution using Lodash:

下面是另一个使用Lodash的解决方案:

var _ = require('lodash');

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'johnny@example.com'},
    {id:4, name:'Bobby', email:'bobby@example.com'}
];

// filter all those that do not match
var result = types1.filter(function(o1){
    // if match found return false
    return _.findIndex(types2, {'id': o1.id, 'name': o1.name}) !== -1 ? false : true;
});

console.log(result);

#1


28  

Just using the Array iteration methods built into JS is fine for this:

仅仅使用构建在JS中的数组迭代方法就可以做到这一点:

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'johnny@example.com'},
    {id:4, name:'Bobby', email:'bobby@example.com'}
];

var props = ['id', 'name'];

var result = result1.filter(function(o1){
    // filter out (!) items in result2
    return !result2.some(function(o2){
        return o1.id === o2.id;          // assumes unique id
    });
}).map(function(o){
    // use reduce to make objects with only the required properties
    // and map to apply this to the filtered array as a whole
    return props.reduce(function(newo, name){
        newo[name] = o[name];
        return newo;
    }, {});
});

document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 4) +
        '</pre>';

If you are doing this a lot, then by all means look at external libraries to help you out, but it's worth learning the basics first, and the basics will serve you well here.

如果您经常这样做,那么请务必查看外部库以帮助您解决问题,但是首先值得学习基础知识,基础知识将在这里很好地为您服务。

#2


9  

The same result can be achieved using Lodash.

使用Lodash也可以达到相同的结果。

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'johnny@example.com'},
    {id:4, name:'Bobby', email:'bobby@example.com'}
];

var result3 = _(result1) 
        .differenceBy(result2, 'id', 'name')
        .map(_.partial(_.pick, _, 'id', 'name'))
        .value();

console.log(result3);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>

You can get the desired result applying a difference between both arrays using the properties "id" and "name" as a way to "link" elements between them. If any of those properties are different, the elements are considered different (improbably in your case because id seems to be unique).

您可以使用属性“id”和“name”在两个数组之间应用一个差异,作为在它们之间“链接”元素的一种方式,获得所需的结果。如果这些属性中有任何一个是不同的,那么元素就会被认为是不同的(在您的例子中,可能是不同的,因为id似乎是唯一的)。

Lastly, you have to map the result in order to "omit" the undesired properties of the object.

最后,您必须映射结果,以便“忽略”对象的不希望的属性。

Hope it helps.

希望它可以帮助。

#3


7  

well, this using lodash or vanilla javascript it depends on the situation.

这个使用lodash或vanilla javascript取决于情况。

but for just return the array that contains the duplicates it can be achieved by the following, offcourse it was taken from @1983

但是仅仅返回包含重复的数组,它就可以通过以下方法实现,当然它是从@1983获得的

var result = result1.filter(function (o1) {
    return result2.some(function (o2) {
        return o1.id === o2.id; // return the ones with equal id
   });
});
// if you want to be more clever...
let result = result1.filter(o1 => result2.some(o2 => o1.id === o2.id));

#4


4  

I have searched a lot for a solution in which I can compare two array of objects with different attribute names (something like a left outer join). I came up with this solution. Here I used Lodash. I hope this will help you.

我已经寻找了很多解决方案,在其中我可以比较具有不同属性名称的两个对象数组(类似于左外连接)。我想到了这个解决方案。在这里我用Lodash。我希望这能对你有所帮助。

var Obj1 = [
    {id:1, name:'Sandra'},
    {id:2, name:'John'},   
];

var Obj2 = [
    {_id:2, name:'John'},
    {_id:4, name:'Bobby'}
];

var Obj3 = lodash.differenceWith(Obj1, Obj2, function (o1, o2) {
    return o1['id'] === o2['_id']
});

console.log(Obj3);
//  {id:1, name:'Sandra'}

#5


2  

Check out difference and xor in lodash.

在lodash中检查差异和xor。

#6


0  

Here is another solution using Lodash:

下面是另一个使用Lodash的解决方案:

var _ = require('lodash');

var result1 = [
    {id:1, name:'Sandra', type:'user', username:'sandra'},
    {id:2, name:'John', type:'admin', username:'johnny2'},
    {id:3, name:'Peter', type:'user', username:'pete'},
    {id:4, name:'Bobby', type:'user', username:'be_bob'}
];

var result2 = [
    {id:2, name:'John', email:'johnny@example.com'},
    {id:4, name:'Bobby', email:'bobby@example.com'}
];

// filter all those that do not match
var result = types1.filter(function(o1){
    // if match found return false
    return _.findIndex(types2, {'id': o1.id, 'name': o1.name}) !== -1 ? false : true;
});

console.log(result);