3

I have the following data:

const myArr = [{
  id: 0,
  company: "microsoft",
  location: "berlin"
}, {
  id: 1,
  company: "google",
  location: "london"
}, {
  id: 2,
  company: "twitter",
  location: "berlin"
}];

let myObj = {
  company: ["google", "twitter"],
  location: ["london"]
}

and given that the myObj.company entries are changing (irrelevant how) I am trying to create a function that filters results and only returns Objects that satisfy the location and company criteria.

In the example above, what we need returned is :

{ 
  id: 1,
  company: "google",
  location: "london"
}

If myObj was

let myObj = {
  company: ["google", "twitter"],
  location: []
}

then the returned result should be

{ 
  id: 1,
  company: "google",
  location: "london"
},
{ 
  id: 2,
  company: "twitter",
  location: "berlin"
}
5
  • What's the expected result of that example you gave?? Commented Feb 10, 2017 at 16:57
  • What is the problem with your iteration? Please add the code you've tried to the question too. Commented Feb 10, 2017 at 16:57
  • just rephrased my question. , will edit it more. Commented Feb 10, 2017 at 16:58
  • Array.prototype.filter() + Array.prototype.some() Commented Feb 10, 2017 at 16:59
  • Thanks for all the amazing answers, I wasn't expecting such a feedback. Commented Feb 10, 2017 at 22:56

3 Answers 3

2

Use Array#filter method with Array#includes method(for old browser support use Array#indexOf method)

myArr.filter(o => (myObj.company.length == 0 || myObj.company.includes(o.company)) && (myObj.location.length == 0 || myObj.location.includes(o.location)))

const myArr = [{
  id: 0,
  company: "microsoft",
  location: "berlin"
}, {
  id: 1,
  company: "google",
  location: "london"
}, {
  id: 2,
  company: "twitter",
  location: "berlin"
}];

let myObj = {
  company: ["google", "twitter"],
  location: ["london"]
}

console.log(
  myArr.filter(o => (myObj.company.length == 0 || myObj.company.includes(o.company)) && (myObj.location.length == 0 || myObj.location.includes(o.location)))
)

myObj = {
  company: ["google", "twitter"],
  location: []
}

console.log(
  myArr.filter(o => (myObj.company.length == 0 || myObj.company.includes(o.company)) && (myObj.location.length == 0 || myObj.location.includes(o.location)))
)


UPDATE : In case there an n number of properties collection then you need to make some variation, where you can use Object.keys and Array#every methods.

var keys = Object.keys(myObj);

myArr.filter(o => keys.every(k => myObj[k].length == 0 || myObj[k].includes(o[k])))

const myArr = [{
  id: 0,
  company: "microsoft",
  location: "berlin"
}, {
  id: 1,
  company: "google",
  location: "london"
}, {
  id: 2,
  company: "twitter",
  location: "berlin"
}];

let myObj = {
  company: ["google", "twitter"],
  location: ["london"]
}

var keys = Object.keys(myObj);
console.log(
  myArr.filter(o => keys.every(k => myObj[k].length == 0 || myObj[k].includes(o[k])))
)

myObj = {
  company: ["google", "twitter"],
  location: []
}
keys = Object.keys(myObj);
console.log(
  myArr.filter(o => keys.every(k => myObj[k].length == 0 || myObj[k].includes(o[k])))
)

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

1 Comment

thank you. I'm upvoting because 1) didn't know includes ! 2) simplicity and brevity as well as readability.. comment : you are testing every array separately (location, company) so if I have 2-3 different tables with other data it's not going to be so DRY
1

Use Array.prototype.filter, Array.prototype.every and Object.keys to get the desired result like this: (note that obj could have any number of keys, it flexible that way)

const myArr = [{
  id: 0,
  company: "microsoft",
  location: "berlin"
}, {
  id: 1,
  company: "google",
  location: "london"
}, {
  id: 2,
  company: "twitter",
  location: "berlin"
}];

let myObj = {
  company: ["google", "twitter"],
  location: ["london"]
}

function find(arr, obj) {
  // get only the keys from obj that their corresponding array is not empty
  var keys = Object.keys(obj).filter(k => obj[k].length !== 0);

  // return a filtered array of objects that ...
  return arr.filter(o => {
    // ... met the creteria (for every key k in obj, the current object o must have its value of the key k includded in the array obj[k])
    return keys.every(k => {
      return obj[k].indexOf(o[k]) != -1;   
    });
  });
}

console.log(find(myArr, myObj));

1 Comment

Thank you, selecting as correct because: 1/ comments 2/ avoiding unnecessary loops 3/ readable
1

You could filter with iterating the keys of criteria and check the content for equality of if the length of the array is not zero.

const filterBy = (array, criteria) => array.filter(o => 
    Object.keys(criteria).every(k =>
        criteria[k].some(c => c === o[k]) || !criteria[k].length)
);

const myArr = [{ id: 0, company: "microsoft", location: "berlin" }, { id: 1, company: "google", location: "london" }, { id: 2, company: "twitter", location: "berlin" }];

console.log(filterBy(myArr, { company: ["google", "twitter"], location: ["london"] }));
console.log(filterBy(myArr, { company: ["google", "twitter"], location: [] }));
.as-console-wrapper { max-height: 100% !important; top: 0; }

With Array#includes instead of Array#some

const filterBy = (array, criteria) => array.filter(o => 
    Object.keys(criteria).every(k => criteria[k].includes(o[k]) || !criteria[k].length)
);

const myArr = [{ id: 0, company: "microsoft", location: "berlin" }, { id: 1, company: "google", location: "london" }, { id: 2, company: "twitter", location: "berlin" }];

console.log(filterBy(myArr, { company: ["google", "twitter"], location: ["london"] }));
console.log(filterBy(myArr, { company: ["google", "twitter"], location: [] }));
.as-console-wrapper { max-height: 100% !important; top: 0; }

1 Comment

+1 because of the console-wrapper hack :) as well as the very scalable solution, amazing! it does take me a while to read through all those nested array functions though, and in the end we're using, filter, keys, every and some so I'm left wondering if there's a more verbose but also readable way of doing it

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.