5

How can I filter an array with a deeply nested array? Given the following 2 arrays, I need the result to be an array with only the rice cakes and the gluten-free-pizza objects:

const foodsILike = ['gluten-free', 'carb-free', 'flavor-free'];
const foodsAvailable = [
  { name: 'pasta', tags: ['delicious', 'has carbs']}, 
  { name: 'gluten-free-pizza', tags: ['gluten-free']}, 
  { name: 'pizza', tags: ['delicious', 'best meal of the year']},
  { name: 'rice cakes', tags: ['flavor-free']}
]

I tried the following which just returns everything (the 4 objects):

var result = foodsAvailable.filter(function(food) {
  return foodsILike.filter(function(foodILike) {
    return foodILike === food;
  })
})

result
// Array [ Object, Object, Object, Object]
1
  • Can you show example output ? Commented Aug 3, 2017 at 11:11

3 Answers 3

13

You could use Array#some and Array#includes for checking if foodsILike contains a tag.

const foodsILike = ['gluten-free', 'carb-free', 'flavor-free'];
const foodsAvailable = [{ name: 'pasta', tags: ['delicious', 'has carbs'] }, { name: 'gluten-free-pizza', tags: ['gluten-free'] }, { name: 'pizza', tags: ['delicious', 'best meal of the year'] }, { name: 'rice cakes', tags: ['flavor-free'] }]

var result = foodsAvailable.filter(function(food) {
    return food.tags.some(function(tag) {
        return foodsILike.includes(tag);
    });
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

4 Comments

what's a more performant way to do this? If you were deeply nested with large arrays this could get computationally expensive.
@zero_cool, it depends on the structure and the wanted result, like all nodes to the found item or just the item of the nested structure. maybe it could be faseter with an object or map for foodsILike. for speeding, the array methods should be avoided if speed really matters.
@NinaScholz Could you take a look at a question I've posted: stackoverflow.com/questions/51663557/… This is related to my question above
This is great! For anyone finding this later and wanting it reformatted in ES6 like I did, it would be: const result = foodsAvailable.filter(food => food.tags.some(tag => foodsILike.includes(tag));
2

You are missing a length check on your inner filter and you aren't checking the tags array for the value in that inner filter

const foodsILike = ['gluten-free', 'carb-free', 'flavor-free'];
const foodsAvailable = [
  { name: 'pasta', tags: ['delicious', 'has carbs']}, 
  { name: 'gluten-free-pizza', tags: ['gluten-free']}, 
  { name: 'pizza', tags: ['delicious', 'best meal of the year']},
  { name: 'rice cakes', tags: ['flavor-free']}
]

var result = foodsAvailable.filter(function(food) {
  return foodsILike.filter(function(foodILike) {
    // is value in tags array?
    return food.tags.indexOf(foodILike) >-1;
  }).length;// length acts as boolean, any length greater than zero is truthy
});

console.log(result)

Comments

0

You can use array.reduce to reduce your array into desired structure, by checking for the condition i.e. foodsILike contains the tag or not.

The benefit of using array.reduce is that you can modify the structure if you want in the reduce loop itself.

const foodsILike = ['gluten-free', 'carb-free', 'flavor-free'];
const foodsAvailable = [
  { name: 'pasta', tags: ['delicious', 'has carbs']}, 
  { name: 'gluten-free-pizza', tags: ['gluten-free']}, 
  { name: 'pizza', tags: ['delicious', 'best meal of the year']},
  { name: 'rice cakes', tags: ['flavor-free']}
];

let foods = foodsAvailable.reduce((foods, food) => {
  if(foodsILike.some(f => food.tags.indexOf(f) !== -1)) {
    foods.push(food);
  }
  return foods;
},[]);

console.log(foods);

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.