Underscore.js - 势在必行&功能锻炼

时间:2018-03-25 17:29:01

标签: javascript functional-programming underscore.js imperative-programming

我正在学习Underscore.js和高阶函数。我遇到了以下问题,我只是被卡住了。

我不是在寻找讲义,但与此同时,我没有任何地方可以寻求指导。我希望有人至少指出我正确的方向。

命令式与功能性究竟是什么意思?

在完成“功能性”解决方案时,我甚至不知道从哪里开始。

非常感谢有关此主题的任何有用信息。

请注意:我确实理解map(),flatten()和reduce()的作用。我只是不知道如何将它应用于这种情况。

我不明白'功能'究竟意味着什么。我会喜欢任何见解。

var 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,
    },
];

// Underscore.js

// Count the ingredient occurence

// IMPERATIVE example:
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);


// FUNCTIONAL: 
/* chain() together map(), flatten() and reduce() */

var ingredientCount = { "{ingredient name}": 0 };

// ? ? ?

expect(ingredientCount['mushrooms']).toBe(2);

2 个答案:

答案 0 :(得分:1)

你需要把它分解成几部分。首先,您只关心成分,但products包含许多额外信息,因此请使用map来提取成分。

现在你有一系列数组中的成分,但你只想要一个包含所有成分的大数组,所以使用flatten给你。

现在你想要计算成分。您可以将此视为一系列缩减,其中您有一个具有先前计数的对象,对于此当前项,您希望增加计数。这可以使用以空对象开头的reduce来完成。我将保留incrementCount函数的实现作为读者的练习。

const ingredients = _.map(products, p => p.ingredients);
const flatIngredients = _.flatten(ingredients);
const counts = _.reduce(flatIngredients, incrementCount, {});

使用功能代码,将您的数据视为通过一系列转换,每个转换都会让您更接近目标,而不是尝试将所有突变塞进一个大循环。

答案 1 :(得分:-2)

功能意味着每个被调用的函数都有一个返回值,通常没有副作用(&#34;纯&#34;)。它是一种非常适合数据转换的编程风格。

  • map接受一个数组并返回一个数组,其中每个项目都已转换。
  • reduce遍历数组,始终提供先前返回的值以及数组中的下一项,计算新值。可用于计算总和等。
  • flatten将列表列表放入列表中。

&#13;
&#13;
var 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,
    },
];

const result = products.reduce((allIngredients, item) => allIngredients.concat(item.ingredients), [])
   .reduce((counts, ingredient) => { 
     counts[ingredient] ? counts[ingredient]++ : (counts[ingredient] = 1);
     return counts
   }, {})

console.log(result);
&#13;
&#13;
&#13;