1

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! :)

0

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

OP's return false on each negated condition check suggests that they do want an AND evaluation
1

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 }

1 Comment

Thank you so much :) Works like a charme!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.