0

I want to build a filter that depending on how many rules there are, it filters an arrya of objects based on those rules.

I have an array of objects like this:

const myList = [
{name: 'Joe',
 sex: 'male',
 isStared: false,
},
{name: 'Ann',
 sex: 'female',
 isStared: true,
},
{name: 'Gil',
 sex: 'female',
 isStared: true,
},
] 

I also have an object with the rules to fillter by which the user specifies, for example it can be:

const rules = {sex: 'male', isStared: 'false'}

I dont want to hard code it so that it specifically checks for sex === 'male' or isStared === true

But I want, that if there are more are less rules, it checks for those and returns only those that for example are male and are stared.

What i have right now is a hard coded filtering, but if the rules change, it will break:

myList.filter(friend => friend.sex === action.filterQuery.sex && friend.sex.isStared === action.filterQuery.sex)

Any idea how to achieve this?

Thanks.

1

2 Answers 2

2

You can use filter, Object.entries, and every -

const myList = [
{name: 'Joe',
 sex: 'male',
 isStared: false,
},
{name: 'Ann',
 sex: 'female',
 isStared: true,
},
{name: 'Gil',
 sex: 'female',
 isStared: true,
},
] 

const rules = {sex: 'male', isStared: false}  // !

const result =
  myList.filter(item =>
    Object.entries(rules).every(([ k, v ]) =>
      item[k] === v
    )
  )

console.log(result)
// [
//   {
//     "name": "Joe",
//     "sex": "male",
//     "isStared": false
//   }
// ]

!: And watch out, 'false' is not the same as false. Don't wrap booleans in quotes.

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

1 Comment

Object.entries(someObj) gives an array of [ key, value ] pairs. For example Object.entries({ a: 1, b: 2 }) gives [['a',1],['b',2]]
0
const filter_with_ruleset = ruleset => input_arr => input_arr.filter(
  item => Object.entries(ruleset)
    .reduce((accum, curr) => accum && item[curr[0]] === curr[1], true)
);

// Usage
const ruleset_1 = { sex: 'male', isStared: true };
const filter_starred_males = filter_with_ruleset(ruleset_1);

console.log(filter_starred_males(myList));

BUT this only filters by equality, not like by "name.starts_with" or something.

Also just watch out, your original data has a spelling error, it looks like isStared should be isStarred, but as long as you're consistent you'll be fine.

1 Comment

Using reduce means you will continue iterating through ruleset entries even after you found a false result. Ie, no need to accum && ... && ... && ..., after accum becomes false just once, the result will always be false. Array.prototype.every and Array.prototype.some have the short-circuit behaviour we're looking for in this case.

Your Answer

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