Reputation: 65
I'm currently trying to filter an array by multiple filters stored in another array. A filter-object contains the name of the attribute we want to filter, the operator and the condition. So it could look like this:
let filters = [{
attribute: 'id',
operator: '<',
condition: 5
}, {
attribute: 'name',
operator: '=',
condition: 'Max'
}]
And the Array with the item could look like this:
const items = [{
id: 0,
name: 'Max',
nachname: 'Maier'
}, {
id: 1,
name: 'Peter',
nachname: 'Huber'
}, {
id: 2,
name: 'Max',
nachname: 'Brooks'
}, {
id: 3,
name: 'Sara',
nachname: 'Scott'
}, {
id: 4,
name: 'Peter',
nachname: 'Evans'
}]
Can you please help me out?
My current solutions (see below) always returns all elements. So it doesn't filter anything.
items.filter((item) => {
filters.forEach((filter) => {
switch (filter.operator) {
case '<':
if (!(item[filter.attribute] < filter.condition)) return false
break
case '<=':
if (!(item[filter.attribute] <= filter.condition)) return false
break
case '=':
if (!(item[filter.attribute] === filter.condition)) return false
break
case '>':
if (!(item[filter.attribute] > filter.condition)) return false
break
case '>=':
if (!(item[filter.attribute] >= filter.condition)) return false
break
case '*wildcard*':
if (!item[filter.attribute].includes(filter.condition))
return false
break
}
})
return true
})
Thanks in advance! :)
Upvotes: 1
Views: 73
Reputation: 164731
Your main problem is that forEach
callback function return values are not used.
Sounds like what you'd want instead is to use Array.prototype.every()
on your filters
array for every item in items
const filters = [{"attribute":"id","operator":"<","condition":5},{"attribute":"name","operator":"=","condition":"Max"}]
const items = [{"id":0,"name":"Max","nachname":"Maier"},{"id":1,"name":"Peter","nachname":"Huber"},{"id":2,"name":"Max","nachname":"Brooks"},{"id":3,"name":"Sara","nachname":"Scott"},{"id":4,"name":"Peter","nachname":"Evans"}]
const filtered = items.filter(item =>
filters.every(({ attribute, operator, condition }) => {
switch (operator) {
case "<":
return item[attribute] < condition
case ">":
return item[attribute] > condition
case "=":
return item[attribute] == condition
// and so on
}
return true
})
)
console.info(filtered)
.as-console-wrapper { max-height: 100% !important }
Upvotes: 1
Reputation: 55613
You need to return a boolean from the filter callback based on the filters. Right now you are just always returning true
from the callback function passed to filter.
Try something like this:
const doesItemPassFilter = item => filter => {
// your filter logic
}
items.filter(item => filters.every(doesItemPassFilter(item)));
I've based my concept that your filters are "and"'s - meaning that an item has to match them all. If your filters are "or"'s - meaning that an item has to match at least one filter - then just change every
to some
.
Upvotes: 2