4

I am trying to filter some objects in my attempt to understand JS better and I'm using underscore.js

I come from a C# background and am used to LINQ however underscore is not quite the same.

Can you help me filter out this array based on the defined test, the issue I'm having is the array property on the array. The Where operator is diffeernt to C# which is what I'd normally use to filter items.

products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];

it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      //This works but was hoping I could do the mushroom check as well in the same line
      var noNuts = _(products).filter(function (x) { return !x.containsNuts;});

      var noMushrooms = _(noNuts).reject(function(x){ return !_(x.ingredients).any(function(y){return y === "mushrooms";});});


      console.log(noMushrooms);

      var count = productsICanEat.length;
      expect(productsICanEat.length).toBe(count);
  });

4 Answers 4

10

You just need to remove the ! from the reject callback so that it look like this:

var noMushrooms = _(noNuts).reject(function(x){ 
    return _(x.ingredients).any(function(y){return y === "mushrooms";});
});

Otherwise you're rejecting the ones that don't contain mushrooms instead of those that do.

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

5 Comments

DOH! Thanks that did it. Any ideas if its possible to chain it? I've tried but no luck
you need to do _.chain(list) first then you can chain your functions all day long - like so _.chain(myArray).filter(function(){ }).reject(function(){ }) underscorejs.org/#chaining
Looks like .any() is depricated. Underscore now has a _.some() method that returns true or false based on whether there are "some" matches.
@skrile It's not deprecated, any is the alias of some.
Thanks for that @JohnnyHK - I learned something new today :)
6

A more concise way to accomplish this would be with underscore's chain() function:

var noMushrooms = _(products).chain()
    .filter(function (x) { 
        return !x.containsNuts;})
    .reject(function(x){ 
        return _(x.ingredients).any(function(y){
            return y === "mushrooms";
        });
    })
    .value();

1 Comment

You don't need to chain, but chaining this way makes it very clear what operations you are doing to your list.
4

I managed to get my solution all wrapped up into one filter call so thought I'd post it:

products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];

 it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      productsICanEat = _(products).filter(function (x) { return !x.containsNuts && !_(x.ingredients).any(function(y){return y === "mushrooms";});});


      expect(productsICanEat.length).toBe(1);
  });

Comments

4

This will give the desired result

var no_nuts = _.filter(products,function(item) {
         return !item.containsNuts;
       });

var no_mushroom = _.reject(no_nuts,function(item) {
        return _.any(item.ingredients,function(item1) {
            return item1 === "mushrooms"
        }); 
     });

console.log(no_mushroom);

reject() does the opposite of filter(), and any() is equivalent to some method of arrays which returns true when any of the element in the array when passed through a callback returns true.

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.