Reputation: 18155
This question is specific to lodash.
Given two arrays of objects, what is the best way to filter one array with the objects of the other array? I have attempted to put forth a scenario below, and the way I have gone about doing this is using two .forEach
loops, but I would like to know if using lodash there is a better way to go about this type of filtering.
users
.
var users = [
{ 'user': 'barney', 'age': 36, 'active': true },
{ 'user': 'joe', 'age': 40, 'active': false },
{ 'user': 'fred', 'age': 50, 'active': false },
{ 'user': 'fred', 'age': 60, 'active': false },
{ 'user': 'fred', 'age': 70, 'active': false },
{ 'user': 'fred', 'age': 22, 'active': false },
{ 'user': 'fred', 'age': 25, 'active': false },
{ 'user': 'barney', 'age': 40, 'active': false },
{ 'user': 'pebbles', 'age': 1, 'active': true }
];
The array of objects that will filter the users
array is called others
.
var others = [
{ 'user': 'fred', 'age': 60 },
{ 'user': 'fred', 'age': 70},
{ 'user': 'fred', 'age': 22}
];
The desired result based on others
filtering users
is:
[
{ 'user': 'fred', 'age': 60, 'active': false },
{ 'user': 'fred', 'age': 70, 'active': false },
{ 'user': 'fred', 'age': 22, 'active': false }
];
Here is one way to obtain the desired result.
var result = [];
_.forEach(users, function (n, key) {
_.forEach(others, function (n2, key2) {
if (n.user === n2.user && n.age === n2.age) {
result.push(n);
}
});
});
console.log(result);
Here is the example on jsbin.
http://jsbin.com/hapariviya/1/edit?html,js,console,output
Upvotes: 17
Views: 48087
Reputation: 282
If you are using lodash and ES6 syntax.
const users = [
{ 'user': 'barney', 'age': 36, 'active': true },
{ 'user': 'joe', 'age': 40, 'active': false },
{ 'user': 'fred', 'age': 50, 'active': false },
{ 'user': 'fred', 'age': 60, 'active': false },
{ 'user': 'fred', 'age': 70, 'active': false },
{ 'user': 'fred', 'age': 22, 'active': false },
{ 'user': 'fred', 'age': 25, 'active': false },
{ 'user': 'barney', 'age': 40, 'active': false },
{ 'user': 'pebbles', 'age': 1, 'active': true }
];
const filters = [
{ 'user': 'fred', 'age': 60, 'active': false },
{ 'user': 'fred', 'age': 70, 'active': false },
{ 'user': 'fred', 'age': 22, 'active': false }
];
_.filter(users, ({user, age, active}) => {
return _.findIndex(filters, ({user:filterUser, age:filterAge, active:filterActive}) => { return (user == filterUser && age == filterAge && active == filterActive) }) >= 0;
})
Upvotes: 0
Reputation: 14501
You can index the others, and then get the desired results without having to nest loops. It should be a relatively efficient solution, regardless of the amount of data:
// index others by "user + age"
var lookup = _.keyBy(others, function(o) { return o.user + o.age.toString() });
// find all users where "user + age" exists in index, one loop, quick lookup. no nested loops
var result = _.filter(users, function(u) {
return lookup[u.user + u.age.toString()] !== undefined;
});
This gives the same result:
[
{ 'user': 'fred', 'age': 60, 'active': false },
{ 'user': 'fred', 'age': 70, 'active': false },
{ 'user': 'fred', 'age': 22, 'active': false }
];
Interestingly, your original solution was the most performant of all of these answers.
The performance concerns are pretty negligible here. In most cases, the DOM interaction is the main performance bottleneck of the front-end. If you were to run this against huge datasets and noticed the locking, you'd definitely want to optimize it further by using for loops instead of iterating with lodash functions.... but you won't typically come across that kind of data in JavaScript... SQL and others would handle it better.
Upvotes: 11
Reputation: 224
Using ES6 fat arrows and lodash's reject:
const result = _.reject(users, (item) => _.find(others, { user: item.user }));
Upvotes: 5
Reputation: 875
Here is cleaner way i can think of:
var result = _.flatten(_.map(others, function(item){
return _.filter(users, item);
}));
Edit: Apologies JS Bin output was obfuscating the nested array.
Upvotes: 10
Reputation: 7862
var result = _.flatten(_.map(others, function(other){return _.where(users, other);}));
Upvotes: 2