Reputation: 229
I'm trying to filter an array of objects which has objects of array of objects inside. For example, an object in an array would look like this.
list=[...,
{
"types": [
{
"slot": 2,
"type":
{
"url": "http://pokeapi.co/api/v2/type/4/",
"name": "poison"
}
},
{
"slot": 1,
"type":
{
"url": "http://pokeapi.co/api/v2/type/12/",
"name": "grass"
}
}
],
"name": 'bulbasaur'
},...
]
I'm currently filtering the list by its name and the types of objects like this (the this.props.search.search being a string, and the example being an example list of strings that will be adjusted):
let filtered = this.props.pokemons.filter((pokemon)=>{
return pokemon.name.toLowerCase().indexOf(this.props.search.search.toLocaleLowerCase())!==-1;
})
let example = ['fire', 'ice', 'water'];
let filteredx= filtered.filter((pokemon)=>{
return pokemon.types.filter((type)=>{
return example.indexOf(type.type.name)!==-1
}).length>0
})
Is there a method of combining all the filters into one instead of calling
array.filter(...).filter(...)
As in the future, if more filters are added, I'm afraid that it's going to end up looking like
array.filter(...).filter(...).filter(...).filter(...).filter(...)
Any help would be appreciated.
Upvotes: 1
Views: 776
Reputation: 21881
You could define an object which contains a property for every first level property of your pokemon list you want to test. The value would be a predicate with the "test logic" for this property.
const pokemons = [
{"name":"poke1","types":[{"type":{"name":"poison"}},{"type":{"name":"grass"}}]},
{"name":"poke2","types":[{"type":{"name":"fire"}},{"type":{"name":"grass"}}]},
{"name":"poke3","types":[{"type":{"name":"ice"}},{"type":{"name":"water"}}]},
{"name":"poke4","types":[{"type":{"name":"ice"}},{"type":{"name":"grass"}}]}
];
const filterOptions = {
name: (name) => {
return ["poke1", "poke5"].some(x => x === name);
},
types: (types) => {
return ["ice", "water"].some(t => types.some(x => t === x.type.name));
}
};
function filterList(list, options) {
return list.filter(pokemon => {
return Object.keys(options)
.some(key => {
if (key in pokemon) {
return filterOptions[key](pokemon[key]);
}
});
});
}
const filtered = filterList(pokemons, filterOptions);
filtered.forEach(p => console.log(JSON.stringify(p)));
Upvotes: 0
Reputation: 1198
Instead of filtering multiple times, you can combine all the filter conditions in one filter.
Instead of doing this...
let filtered1 = toFilter.filter((element) => {
return condition1;
});
let filtered2 = filtered1.filter((element) => {
return condition2;
});
...
let filteredN = filteredN_1.filter((element) => {
return conditionN;
});
... you can combine the conditions in a single filter:
let filtered = toFilter.filter((element) => {
return condition1 && condition2 && ... && conditionN;
});
If one of the conditions is very long, you can easily abstract it in a separate function. This also makes the code more readable and maintainable.
let filtered = toFilter.filter((element) => {
const condition1 = computeCondition1(arg1, arg2);
const condition2 = computeCondition2(arg1);
...
const condition3 = computeCondition3(arg2, arg3, arg4);
return condition1 && condition2 && ... && conditionN;
});
Upvotes: 0
Reputation: 5537
If the array is small and perfomance not an issue;
const arryOfPokemons = [{name: 'name1', type: 'type1'}];
function name(pokemon) { return pokemon.name !== 'name' }
function type(pokemon) { return pokemon.type !== 'type' }
const result = [name, type].reduce((result, filterFunc) => result.filter(filterFunc), arryOfPokemons);
otherwise you can try to combine the conditions into the same filter function.
Upvotes: 0
Reputation: 350300
You can combine the two conditions with an &&
:
let filteredx = this.props.pokemons.filter(pokemon =>
pokemon.name.toLowerCase().includes(this.props.search.search.toLocaleLowerCase())
&& pokemon.types.some(type => example.includes(type.type.name))
)
Note you can use includes
and some
in your conditions, and use the expression syntax in your arrow functions (without braces nor return
).
You can add more conditions with additional &&
operators. Make sure to put them in such order that the most simple conditions (that require least work) come first.
Upvotes: 1