#javascript #arrays #filter
#javascript #массивы #Фильтр
Вопрос:
В настоящее время я пытаюсь отфильтровать массив по нескольким фильтрам, хранящимся в другом массиве. Объект фильтра содержит имя атрибута, который мы хотим отфильтровать, оператор и условие. Так что это может выглядеть так:
let 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'
}]
Не могли бы вы, пожалуйста, помочь мне?
Мои текущие решения (см. Ниже) всегда возвращают все элементы. Таким образом, он ничего не фильтрует.
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
})
Заранее спасибо! 🙂
Ответ №1:
Вам нужно вернуть логическое значение из обратного вызова фильтра на основе фильтров. Прямо сейчас вы просто всегда возвращаетесь true
из функции обратного вызова, переданной filter .
Попробуйте что-то вроде этого:
const doesItemPassFilter = item => filter => {
// your filter logic
}
items.filter(item => filters.every(doesItemPassFilter(item)));
Я основал свою концепцию на том, что ваши фильтры — это «и», что означает, что элемент должен соответствовать им всем. Если ваши фильтры имеют значение «или», что означает, что элемент должен соответствовать хотя бы одному фильтру, тогда просто измените every
на some
.
Комментарии:
1. OP
return false
при каждой проверке отрицаемого условия предполагает, что они действительно хотятAND
оценки
Ответ №2:
Ваша основная проблема заключается в том, что forEach
возвращаемые значения функции обратного вызова не используются.
Похоже, вместо этого вы хотели бы использовать Array.prototype.every()
в своем filters
массиве для каждого элемента в 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 }
Комментарии:
1. Большое вам спасибо 🙂 Работает как шарм!