Underscore.js - 命令式和功能性练习
Underscore.js - Imperative & Functional exercise
我正在学习 Underscore.js 和高阶函数。我遇到了以下问题,我只是被卡住了。
我不是在寻找讲义,但与此同时,我也没有任何地方可以寻求这方面的指导。我希望有人能至少为我指明正确的方向。
命令式与函数式究竟是什么意思?
在完成 'functional' 解决方案时,我什至不知道从哪里开始。
如能提供有关此主题的任何有用信息,我们将不胜感激。
请注意:我确实理解 map()、flatten() 和 reduce() 的作用。我只是不知道如何将它应用于这种情况。
我不明白 'functional' 的真正含义。我会喜欢任何见解。
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);
函数式意味着每个被调用的函数都有一个 return 值并且通常没有副作用 ("pure")。是一种非常适合数据转换的编程风格。
map
接受一个数组,returns 一个数组,每个项目都被转换。
reduce
遍历数组,始终提供先前 returned 的值和数组中的下一项,计算新值。可用于计算总和等。
flatten
将列表的列表变成列表。
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);
你需要把它分解成几个部分。首先,你只关心成分,但是 products
包含很多额外的信息,所以使用 map
只提取成分。
现在你在一组数组中有成分,但你只想要一个包含所有成分的大数组,所以使用 flatten
给你。
现在你要清点配料。您可以将其视为一系列减少,其中您有一个具有先前计数的对象,并且对于当前项目,您想要增加计数。这可以使用以空对象开头的 reduce
来完成。我将 incrementCount
函数的实现留作 reader.
的练习
const ingredients = _.map(products, p => p.ingredients);
const flatIngredients = _.flatten(ingredients);
const counts = _.reduce(flatIngredients, incrementCount, {});
使用函数式代码,将您的数据视为通过一系列转换,每个转换都让您更接近您的目标,而不是一个您试图将所有突变塞入的大循环。
我正在学习 Underscore.js 和高阶函数。我遇到了以下问题,我只是被卡住了。
我不是在寻找讲义,但与此同时,我也没有任何地方可以寻求这方面的指导。我希望有人能至少为我指明正确的方向。
命令式与函数式究竟是什么意思?
在完成 'functional' 解决方案时,我什至不知道从哪里开始。
如能提供有关此主题的任何有用信息,我们将不胜感激。
请注意:我确实理解 map()、flatten() 和 reduce() 的作用。我只是不知道如何将它应用于这种情况。
我不明白 'functional' 的真正含义。我会喜欢任何见解。
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);
函数式意味着每个被调用的函数都有一个 return 值并且通常没有副作用 ("pure")。是一种非常适合数据转换的编程风格。
map
接受一个数组,returns 一个数组,每个项目都被转换。reduce
遍历数组,始终提供先前 returned 的值和数组中的下一项,计算新值。可用于计算总和等。flatten
将列表的列表变成列表。
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);
你需要把它分解成几个部分。首先,你只关心成分,但是 products
包含很多额外的信息,所以使用 map
只提取成分。
现在你在一组数组中有成分,但你只想要一个包含所有成分的大数组,所以使用 flatten
给你。
现在你要清点配料。您可以将其视为一系列减少,其中您有一个具有先前计数的对象,并且对于当前项目,您想要增加计数。这可以使用以空对象开头的 reduce
来完成。我将 incrementCount
函数的实现留作 reader.
const ingredients = _.map(products, p => p.ingredients);
const flatIngredients = _.flatten(ingredients);
const counts = _.reduce(flatIngredients, incrementCount, {});
使用函数式代码,将您的数据视为通过一系列转换,每个转换都让您更接近您的目标,而不是一个您试图将所有突变塞入的大循环。