Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript: Filter list of objects by a list of filter objects

I have currently two different lists of objects, one which needs to filter the other. Here is how they currently look.

var heroes = [
    {
      name: "warrior",
      primary_skill: "greater bash",
      attack_type: "melee",
      attribute: "strength"
    },
    {
      name: "ranger",
      primary_skill: "focus fire",
      attack_type: "range",
      attribute: "agility"
    },
    {
      name: "mage",
      primary_skill: "oblivion",
      attack_type: "magic",
      attribute: "intelligence"
    },
    {
      name: "soldier",
      primary_skill: "sword dance",
      attack_type: "melee",
      attribute: "strength"
    }
]

Which should be filtered by the following

var filters = [
    { attack_type: "melee" },
    { attribute: "strength" }
]

The filters should work in an "and" fashion, so this would filter the list of heroes so that only melee heroes that have the strength attribute are shown.

Here is the attempt that I have so far, but I'm not making much progress:

const filteredHeroes = heroes.filter(
    hero => {
        return filters.some( 
            filter => {
                return filter.attack_type === hero.attack_type &&
                filter.primary_skill === hero.primary_skill &&
                filter.attribute === hero.attribute
            }
        )
    }
)

I understand this filter function makes no sense.. But I do not know the correct way to do what I require.

Ideally the function that applies the filters is agnostic about the properties that are included, so that if the data set was to include a new property that isn't currently present, the filters array could accept that and the function that applies them doesn't require any updates.

I do not wish to include any external libraries, backwards compatibility is not a huge concern - as long as it works in IE11 and all other modern browsers.

like image 967
Dale Avatar asked Apr 06 '18 08:04

Dale


People also ask

Can you filter an array of objects in JavaScript?

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.

Can you chain filter JavaScript?

Since the filter method returns an array we can chain it to the map method which works on an array and vice-versa. This process can be applied to all the array methods which makes the code concise.

How do you filter objects in JavaScript?

keys() to filter an Object. After you've generated the keys, you may use filter() to loop over the existing values and return just those that meet the specified criteria. Finally, you can use reduce() to collect the filtered keys and their values into a new object, for instance.


1 Answers

Use filter and every

heroes.filter( s => //for every object in heroes
    filters.every( t => { //check if every filter in iteration has the same value or not
       var key = Object.keys(t)[0]; 
       return s[key] == t[key]
    })
);

Demo

var heroes = [{
    name: "warrior",
    primary_skill: "greater bash",
    attack_type: "melee",
    attribute: "strength"
  },
  {
    name: "ranger",
    primary_skill: "focus fire",
    attack_type: "range",
    attribute: "agility"
  },
  {
    name: "mage",
    primary_skill: "oblivion",
    attack_type: "magic",
    attribute: "intelligence"
  },
  {
    name: "soldier",
    primary_skill: "sword dance",
    attack_type: "melee",
    attribute: "strength"
  }
];
var filters = [{
    attack_type: "melee"
  },
  {
    attribute: "strength"
  }
];

var output = heroes.filter(s => filters.every(t => {
  var key = Object.keys(t)[0];
  return s[key] == t[key]
}));

console.log(output);

For IE11 compatibility, use normal functions (don't use arrow functions) and polyfill for every

var output = heroes.filter( function(s){ 
     return filters.every( function(t) {
        var key = Object.keys(t)[0];
        return s[key] == t[key]
     });
});
like image 158
gurvinder372 Avatar answered Oct 29 '22 20:10

gurvinder372