Reputation: 40032
I am trying to learn JS better.
I have the below code which I am trying to put into underscore.js but am failing.
I'm hoping you can point out where I'm going wrong.
I'm trying to take a loop that I know works and then use underscores capabilites to refine it. The top test shows the loops, the second test is my attempt to do the same with underscore.js. I'm failing miserably!
Thanks
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("should count the ingredient occurrence (imperative)", function () {
var ingredientCount = { "{ingredient name}": 0 };
for (i = 0; i < products.length; i+=1) {
for (j = 0; j < products[i].ingredients.length; j+=1) {
ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
}
}
expect(ingredientCount['mushrooms']).toBe(2);
});
it("should count the ingredient occurrence (functional)", function () {
var ingredientCount = { "{ingredient name}": 0 };
var ffd = _(products).chain()
.map(function(x){return x.ingredients;})
.flatten()
.reduce(function(memo,x){
if (x===memo)
{
return ingredientCount[memo] = ingredientCount[memo]+1;
}
else
{
return ingredientCount[memo] = 0;
}
})
.value();
/* chain() together map(), flatten() and reduce() */
expect(ingredientCount['mushrooms']).toBe(2);
});
Upvotes: 1
Views: 2249
Reputation: 99
I'd use simpler to understand code, though it is not functional:
it("should count the ingredient occurrence (functional)", function () {
var ingredientCount = { "{ingredient name}": 0 };
var dummy = _(products).chain()
.pluck("ingredients")
.flatten()
.each(function(x) { ingredientCount[x] = (ingredientCount[x] || 0) + 1; })
.value();
expect(ingredientCount['mushrooms']).toBe(2);
});
Upvotes: 0
Reputation: 664484
Your reduce is not very functional. Have a look at its documentation! The "memo", also know as "accumulator", is the value returned from the previous iteration - that should be your ingredientCount
map.
var ingredientCount = _.chain(products)
.pluck("ingredients") // don't use map for that
.flatten()
.reduce(function (memo, item) {
memo[item] = (memo[item] || 0)+1;
/* alternative:
if (item in memo)
memo[item]++;
else
memo[item] = 1;
*/
return memo; // to be used in the next iteration!
}, {/*"{ingredient name}": 0*/})
.value();
Notice that memo === ingredientCount
!
Upvotes: 3