Filtering array with underscore.js

2019-02-18 09:02发布

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条回答
【Aperson】
2楼-- · 2019-02-18 09:37

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.

查看更多
不美不萌又怎样
3楼-- · 2019-02-18 09:45

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();
查看更多
ら.Afraid
4楼-- · 2019-02-18 09:50

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.

查看更多
爷、活的狠高调
5楼-- · 2019-02-18 09:51

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);
  });
查看更多
登录 后发表回答