Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS Array.filter with Dynamic Filter Criterion

Tags:

javascript

How can I dynamically declare a set of filters criteria without having to specify the number of filters?

For example, if I have a set of data, like this:

var data = [ 
  { item: { type: 'wood', size: 10 } }, 
  { item: { type: 'wood', size: 8 } },
  { item: { type: 'metal', size: 8 } } 
]

I Know that I can use JS .filter() to get all of the items that have type wood and size 8:

function filterItems() {
  return data.filter(function(val) {
    return val['item'].type == 'wood' && 
           val['item'].size == 8;
  }
}

But what if I want to filter the items with an unknown number of filters, and have .filter() return all data items that match those criterion?

Here is a codepen that reflects the above code.

like image 399
Himmel Avatar asked Dec 04 '22 03:12

Himmel


2 Answers

You could pass an array of conditions to the filterItems() function. Try this:

function filterItems(filters) {
  return data.filter(function(val) {
    for(var i = 0; i < filters.length; i++)
      if(val['item'][filters[i][0]] != filters[i][1])
        return false;
    return true;
  }
}
filterItems([['type', 'wood'], ['size', 8], ['someother', 'value']]);

The same idea can be applied in various formats, such as using objects instead of an array for increased readability.

like image 64
Amit Avatar answered Dec 09 '22 14:12

Amit


I just did some one line refactor on Amit's answer for any data structure and nested properties support

// the function
filterItems = (data, filters) => data.filter(item => !filters.find(x => x.key.split('.').reduce((keys, key) => keys[key], item) !== x.value))

// how to use it
filterItems(data, [{ key: 'type', value: 'wood' }, { key: 'some.nested.prop', value: 'value' }])
like image 38
Christopher Kiessling Avatar answered Dec 09 '22 14:12

Christopher Kiessling