Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lodash: filter array of objects with a different array of objects

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.


Example
The main source array of objects is 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

like image 439
mg1075 Avatar asked Apr 30 '15 21:04

mg1075


People also ask

How do you filter an array of objects based on another array?

One can use filter() function in JavaScript to filter the object array based on attributes. The filter() function will return a new array containing all the array elements that pass the given condition. If no elements pass the condition it returns an empty array.

Does filter manipulate the array?

The filter() method creates a new array filled with elements that pass a test provided by a function. The filter() method does not execute the function for empty elements. The filter() method does not change the original array.

Does filter modify the original array Swift?

Yes, the . filter() method returns a new array, without the filtered elements in the same order as initially. The order of the elements is one of the main feature of a array.


1 Answers

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.

http://jsperf.com/testingdiwq

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.

like image 123
Cory Danielson Avatar answered Oct 13 '22 02:10

Cory Danielson