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.
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.
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.
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.
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]
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With