0

Trying to wrap my brain around how I should tackle filtering an array of objects and only returning results that satisfy all of the tags.

The tags could be any of the fields - fname/lname/email/position/etc

let search_tags = ['CEO', 'Steven'];

let contacts = [
  { fname: 'Steve', lname: 'Johnson', email: '[email protected]', position: 'CEO' },
  { fname: 'James', lname: 'Laurence', email: '[email protected]', position: 'CFO' }
]

let results = contacts.filter((contact) => {
  if (search_tags.includes(contact.fname) || 
      search_tags.includes(contact.lname) ... ) {
    return contact;
  }
}

I shortened a bit of the code for brevity and obviously this solution will return contacts that match any search_tag but... I need to only return results that satisfy every search_tag.

It's been a long day and I have no one to talk this through so I'm hoping someone may be able to point me in the right direction or give me that ah-ha! moment I'm hoping for :)

Thanks in advance!

2
  • use && rather than || Commented Mar 1, 2018 at 2:26
  • If you are just looking to be pointed in the right direction: turn search_tags into a Set object then for each object in contacts, create a set of the field values, then do a set intersection or symmetric difference. Let us know if you need help doing that. Commented Mar 1, 2018 at 2:27

3 Answers 3

0

If you wanted to return one that matched every search tag you'd want to use && instead of || but that still leaves you with a bunch of verbose and duplicated code

Instead of operating directly on the contact Object, you can use Object.values() https://mdn.io/objectvalues which would give you an array of ['steve', 'johnson', 'user@domain]... etc.

Then you could in your filter:

contacts.filter((contact) => {
    const contactValues = Object.values(contact);
    // Return the search item if at least one item matches
    // Would return true if at least one item matches
    return contactValues.some(value => search_tags.includes(value));
    // return true only if all search tags match
    return contactValues.every(value => search_tags.includes(value));
}

Object.values is quite a new feature, so if you don't have it available in babel, then you can use Object.keys and grab the value using contact[someKey]

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

2 Comments

Your second return will never be hit.
@Geuis I think it is included as a "template" and OP is expected to keep one of the two
0

Array.prototype.filter() can be combined with Array.prototype.every(), Object.values() and Array.prototype.includes() to construct an Array of matches consisting solely of contact Objects that contain a matching value for every element in search_tags.

See below for a practical example.

// Search Tags.
const search_tags = ['CEO', 'Steven']

// Contacts.
let contacts = [
  { fname: 'Steven', lname: 'Johnson', email: '[email protected]', position: 'CEO' },
  { fname: 'James', lname: 'Laurence', email: '[email protected]', position: 'CFO' }
]

// Matches.
const matches = contacts.filter((contact) => search_tags.every((tag) => Object.values(contact).includes(tag)))

// Log.
console.log(matches)

Comments

0

ES6:

function filterIt(arr, searchKeys) {
  return arr.filter(obj => Object.keys(obj).some(key => searchKeys.includes(obj[key])));
}

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.