'filter array based on array of multiple condition
I Would like to return the two last object based on the filterArray because filterArray contain 'Orange' as tags and 'Fruit' as type. but because all my obj contain an array of tags the function includes doesn't work. (works only if the value tags is a string).
const filterArray = [
{ type: 'type', value: ['Fruit'] },
{ type: 'tags', value: ['Apple', 'Orange', 'Peach'] },
]
const obj = [
{ type: 'Sweet Fruit', tags: ['Apple'] },
{ type: 'Fruit', tags: ['Orange', 'Watermelon'] },
{ type: 'Fruit', tags: ['Orange'] },
]
const Newresult = obj.filter(item =>
filterArray.every(({ type, value }) => value.includes(item[type])),
)
console.log(Newresult)
this function works if the const obj.tags is not an array but string.
Solution 1:[1]
You could use the following:
// use a set in the filter so lookups happen in O(1)
const filter = [
{ type: "type", value: new Set(["Fruit"]) },
{ type: "tags", value: new Set(["Apple", "Orange", "Peach"]) },
];
const obj = [
{ type: "Sweet Fruit", tags: ["Apple"] },
{ type: "Fruit", tags: ["Orange", "Watermelon"] },
{ type: "Fruit", tags: ["Orange"] },
];
const Newresult = obj.filter((item) => (
filter.every(({ type, value }) => {
// check whether the value we want to filter by is an arry
if(Array.isArray(item[type])){
// yes, we are dealing with an array => check if any of the filter criteria are matched
// if you want to check for all criteria use "every()" instead of "some"
return item[type].some(valueInArray => value.has(valueInArray));
}
// if we are not dealing with an array we need to just check one value
return value.has(item[type]);
})
));
console.log(Newresult);
Key changes to your approach:
- I check whether I am dealing with an Array and if I do, I check if any of the values within the array is within the whitelist values provided by the filter
- I use a
Set
instead of an array which reduces the time for lookupsO(n)
for arrays to0(1)
and therefore significantly speeds up the algorithm.
Solution 2:[2]
You could treat every value of data as array and check if the data contians a value from the filter.
const
filter = [{ type: 'type', value: ['Fruit'] }, { type: 'tags', value: ['Apple', 'Orange', 'Peach'] }],
data = [{ type: 'Sweet Fruit', tags: ['Apple'] }, { type: 'Fruit', tags: ['Orange', 'Watermelon'] }, { type: 'Fruit', tags: ['Orange'] }, ],
result = data.filter(o => filter.every(({ type, value }) => []
.concat(o[type])
.some(v => value.includes(v))
));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Mushroomator |
Solution 2 | Nina Scholz |