2

given the following structure:

let filteredTasks = [
  {status: 'done', other: true},
  {status: 'nope', other: false},
  {status: 'done', other: true},
  {status: 'done', other: true},
  {status: 'done', other: false},
  {status: 'done', other: false},
  {status: 'started', other: false}
]

and:

let availableFilters = [{status: 'done'}, {other: false}]

how can I filter this array to get the following results:

filteredTasks =
[{status: 'done', other: false}, {status: 'done', other: false}]

my thoughts and attempts:

let filteredTasks = [
  {status: 'done', other: true},
  {status: 'nope', other: false},
  {status: 'done', other: true},
  {status: 'done', other: true},
  {status: 'done', other: false},
  {status: 'done', other: false},
  {status: 'started', other: false}
]

let availableFilters = [{status: 'done'}, {other: false}]

let filteredTasksList = availableFilters.map(item => {
    return runFilter(item)
})

function runFilter(currentFilter) {
  return filteredTasks.filter(item => {
    for (var key in currentFilter) {
        if (item[key] === undefined || item[key] !== currentFilter[key])
        return false
    }
    return true;
  })
}

...but obviously this is overriding each pass.

As always any feedback and help is greatly appreciated, so thanks in advance.

EDIT: accepted the initial comment as the solution as it fits my needs. I used that to take it a step further:

let filterTaskList = (list, filters) => {
  let entries = Object.entries(Object.assign(...filters))
  return list.filter(task => {
    return entries.every(([key, val]) => {
      return task[key] === val
     })
  })
}
1
  • Is every separate object in availableFilters supposed to represent a key->value match? Commented Dec 11, 2018 at 18:49

2 Answers 2

5

You could create a single object of the filters and take the entries for filtering.

let filteredTasks = [
  {status: 'done', other: true},
  {status: 'nope', other: false},
  {status: 'done', other: true},
  {status: 'done', other: true},
  {status: 'done', other: false},
  {status: 'done', other: false},
  {status: 'started', other: false}
],
 availableFilters = [{status: 'done'}, {other: false}], // your filters
  filters = Object.entries(Object.assign(...availableFilters)), // returns an array of the filter's own enumerable property
  result = filteredTasks.filter(o => filters.every(([k, v]) => o[k] === v)); // .every returns true, when every item is fulfilling the condition
  
console.log(result);
  

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

3 Comments

What if filteredTasks object are like this {value: {status: 'done', other: true}} and availableFilters should be [{value: {status: 'done'}}, {value:{other: false}}] Can it work like this also?
I'm guessing o[k] === v should be replaced with deep equal
it depends if you have more properties in the first level or if the first level is a constant value. if you have a dynamic properties, you need to get all nested entries and take this for filtering.
1

Code first:

let filteredTasks = [
  {status: 'done', other: true},
  {status: 'nope', other: false},
  {status: 'done', other: true},
  {status: 'done', other: true},
  {status: 'done', other: false},
  {status: 'done', other: false},
  {status: 'started', other: false}
]

let availableFilters = [{status: 'done'}, {other: false}]

const matchesFilter = (filter, item) => Object.entries(filter).every(([key, value]) => item[key] === value)

function withFilters (filters) {
  return item => filters.every(f => matchesFilter(f, item))
}

console.log(filteredTasks.filter(withFilters(availableFilters)))

Explanation: the two interesting functions here are matchesFilter and withFilters.

matchesFilter: takes an object, the filter and compares every key/value to the item to ensure it matches.

withFilters takes in a list of filters and returns a function that can be used with Array.prototype.filter to produce a filtered list.

You then just use withFilters(availableFilters) as your filter function. You can even save that result to re-use it later.

let filterByAvailable = withFilters(availableFilters)
let availableTaks = filteredTasks.filter(filterByAvailable)

Comments

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.