potterzot
potterzot

Reputation: 648

How to filter a javascript object array with variable parameters

I want to select the objects based on the properties of the objects, but not always the same properties. In other words:

arr = [
    { name: "joe",   age21: 1 },
    { name: "nick",  age21: 0 },
    { name: "blast", age21: 1 }
];

arr.filter(function(item) {
    return (item.name === "nick" && item.age21 === 1);
});

But sometimes I just want to filter on name for example:

arr.filter(function(item) {
    return (item.name === "nick");
});

What I want to do is generalize this so that the list of parameters can be passed to the function. I've come up with the following, but it's slow and I'm wondering if there is a better way:

filterParams = function(arr, params) {
    var new_array = arr.filter(function(item) {
        var select = 1
        for(obj in params) { //create the filter criteria based on varying set of parameters
            var select = select && params[obj] === item[obj];
        }
        return select;
    });
    return new_array;
}

Then you could call it with: filterParams(arr, {name: "nick", age21: 1});

or with: filterParams(arr, {name: "nick"});

and it would work either way.

In case you're wondering, I'm doing this because I have different data sets that I want to run through the same routine, so the filter properties need to be generalized so that I can filter on properties specific to each dataset.

Thanks!

Upvotes: 20

Views: 49483

Answers (1)

elclanrs
elclanrs

Reputation: 94101

Here's a functional approach that should work for any numbers of properties given the object:

function filter(arr, criteria) {
  return arr.filter(function(obj) {
    return Object.keys(criteria).every(function(c) {
      return obj[c] == criteria[c];
    });
  });
}

For example:

var arr = [
  { name: 'Steve', age: 18, color: 'red' },
  { name: 'Louis', age: 21, color: 'blue' }, //*
  { name: 'Mike', age: 20, color: 'green' },
  { name: 'Greg', age: 21, color: 'blue' }, //*
  { name: 'Josh', age: 18, color: 'red' }
];

console.log(filter(arr, { age: 21, color: 'blue' }));
//^ {age:21, color:'blue', name:'Louis}
//  {age:21, color:'blue', name:'Greg'}

Not sure about your performance issue, but this should be OK.

Edit: You could make this more powerful with regular expressions, something like this:

function filter(arr, criteria) {
  return arr.filter(function(obj) {
    return Object.keys(criteria).every(function(c) {
      return new RegExp(criteria[c]).test(obj[c]);
    });
  });
}

console.log(filter(arr, { age: /^2\d$/, color: /^(red|blue)$/ }));
//^ Louis, Greg                --^-- twenty-something
//                                               ----^---- red OR blue

Upvotes: 51

Related Questions