Массив фильтров JavaScript с фильтрами другого массива

#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. Большое вам спасибо 🙂 Работает как шарм!