38

I'm playing around with arrays trying to understand them more since I tend to work with them alot lately. I got this case where I want to search an array and compare it's element values to another array which contains values of some selected filters.

For example if I select 3 filters, I want later to write matches in new array - only those which match all 3 filters.

For easier understanding I set up an example on http://jsfiddle.net/easwee/x8U4v/36/

Code is:

var workItems =   [
    { "id": 2616, "category": ".category-copy .category-beauty .category-fashion"}, //this is a match
    { "id": 1505, "category": ".category-beauty"}, // NOT
    { "id": 1500, "category": ".category-beauty .category-fashion"}, // NOT
    { "id": 692, "category": ".category-stills .category-retouching"}, // NOT
    { "id": 593, "category": ".category-beauty .category-capture .category-fashion .category-product .category-stills .category-stills-retouching "}, // NOT
    { "id": 636, "category": ".category-beauty .category-copy .category-fashion"}, //this is a match
    { "id": 547, "category": ".category-fashion .category-lifestyle .category-stills .category-stills-retouching "}, // NOT
    { "id": 588, "category": ".category-capture .category-recent-work .category-copy .category-beauty .category-fashion"} //this is a match
];

var filtersArray = [".category-beauty", ".category-fashion", ".category-copy"];

var i;
for (i = 0; i < filtersArray.length; ++i) {
    var searchString = filtersArray[i];
    console.log('Searching for: ' + searchString);
    var filtered = $(workItems).filter(function(){
        return this.category.indexOf(searchString);
    });    
}   
console.log('Filtered results: ' + JSON.stringify(filtered, null, 4));

I also tried with

filtered = $.grep(workItems, function(element, index){
    return element.category.indexOf(filtersArray[i]); 
}, true);

but it matches only the first filter and only if it's at the begining of workItems.category

I've tried many different solutions but can't really make this work. What function should I use to return the desired result?

easwee
  • 15,757
  • 24
  • 60
  • 83

4 Answers4

25

You can use .filter() method of the Array object:

var filtered = workItems.filter(function(element) {
   // Create an array using `.split()` method
   var cats = element.category.split(' ');

   // Filter the returned array based on specified filters
   // If the length of the returned filtered array is equal to
   // length of the filters array the element should be returned  
   return cats.filter(function(cat) {
       return filtersArray.indexOf(cat) > -1;
   }).length === filtersArray.length;
});

http://jsfiddle.net/6RBnB/

Some old browsers like IE8 doesn't support .filter() method of the Array object, if you are using jQuery you can use .filter() method of jQuery object.

jQuery version:

var filtered = $(workItems).filter(function(i, element) {
   var cats = element.category.split(' ');

    return $(cats).filter(function(_, cat) {
       return $.inArray(cat, filtersArray) > -1;
    }).length === filtersArray.length;
});
Ram
  • 143,282
  • 16
  • 168
  • 197
  • 1
    `Array.prototype.filter` needs ECMAScript 5 support and only is available on modern browsers, i think for these basic works our own written functions is better, Aside from this, it's a cross-browser solution – frogatto Sep 10 '13 at 13:14
  • Cool, the last line could be simplified using `Array.prototype.every`. Like this: `return filtersArray.every(function(cat) { return ~cats.indexOf(cat); })` – Yury Tarabanko Sep 10 '13 at 13:22
  • I'm using jQuery - so I guess this solution will work. Atleast it matched any tests I sent in and IE8 is not really a problem in this case since this is mostly practice work. Thanks a lot for help! – easwee Sep 10 '13 at 13:22
  • @ABFORCE Well, if you really care about cross-browser issues, you should know that IE8 doesn't support `indexOf` method of array object, the only browser that makes problem is IE, most previous versions of other browsers support most of the ECMAScript 5 methods, even Firefox v1, btw your answer doesn't solve the issue. – Ram Sep 10 '13 at 13:33
  • Amazing way to filter multiple arrays for multiple values! Exactly what I needed -- thanks! – Maria Blair Jan 16 '19 at 22:02
18

You can use .filter() with boolean operators ie &&:

     var find = my_array.filter(function(result) {
       return result.param1 === "srting1" && result.param2 === 'string2';
     });
     
     return find[0];
Owen Kelvin
  • 14,054
  • 10
  • 41
  • 74
aabiro
  • 3,842
  • 2
  • 23
  • 36
5

The best way would be to have an array of values to search and then loop the data.

const ids = [1,2,3];
const products = DATA.filter((item) => ids?.includes(item.id));
jgatjens
  • 682
  • 1
  • 8
  • 16
0

this trick will help if anyone want to apply filter on the base of more than of property of object.

searchCustomers(){
        let tempCustomers = this.customers
        if (this.searchValue != '' && this.searchValue) {
        
        tempCustomers = tempCustomers.filter((item) => {
          

          return item.name
            .toUpperCase()
            .includes(this.searchValue.toUpperCase()) || item.customer_no
            .toUpperCase()
            .includes(this.searchValue.toUpperCase()) || item.mobno
            .toUpperCase()
            .includes(this.searchValue.toUpperCase()) 
        })
      }
      return tempCustomers;
  }
msayubi76
  • 1,446
  • 1
  • 12
  • 18