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);
});
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.
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();
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);
});
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.