如何使用FP compose()
将两个函数组合成1
这里有实时代码:https://repl.it/JXMl/1
我有3个纯函数:
// groups By some unique key
const groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
// ungroups the group by
const ungroup = (obj) => {
return Object.keys(obj)
.map(x => obj[x]);
};
// flatten array
const flatten = (arrs) => {
return arrs.reduce((acc, item) => acc.concat(item), [])
}
功能实用程序由Functional Jargon
组成函数const compose = (f, g) => (a) => f(g(a))
最后,我希望通过ungroupAndFlatten
创建一个compose()
函数。
遵循:
const ungroupAndFlatten = compose(ungroup, flatten) // Usage doesn't work.
console.log(ungroupAndFlatten(obj))
示例代码:
const arrs = [
{name: 'abc', effectiveDate: "2016-01-01T00:00:00+00:00"},
{name: 'abcd', effectiveDate: "2016-02-01T00:00:00+00:00"},
{name: 'abcd', effectiveDate: "2016-09-01T00:00:00+00:00"},
{name: 'abc', effectiveDate: "2016-04-01T00:00:00+00:00"},
{name: 'abc', effectiveDate: "2016-05-01T00:00:00+00:00"},
];
const groupedByName = groupBy(arrs, 'name');
// Example Output
//
// var obj = {
// abc: [
// { name: 'abc', effectiveDate: '2016-01-01T00:00:00+00:00' },
// { name: 'abc', effectiveDate: '2016-04-01T00:00:00+00:00' },
// { name: 'abc', effectiveDate: '2016-05-01T00:00:00+00:00' }
// ],
// abcd: [
// { name: 'abcd', effectiveDate: '2016-02-01T00:00:00+00:00' },
// { name: 'abcd', effectiveDate: '2016-09-01T00:00:00+00:00' }
// ]
// }
const ungroupAndFlatten = compose(ungroup, flatten) // Usage doesn't work.
console.log(ungroupAndFlatten(groupedByName))
// Output:
// var arrs = [
// {name: 'abc', effectiveDate: "2016-01-01T00:00:00+00:00"},
// {name: 'abcd', effectiveDate: "2016-02-01T00:00:00+00:00"},
// {name: 'abcd', effectiveDate: "2016-09-01T00:00:00+00:00"},
// {name: 'abc', effectiveDate: "2016-04-01T00:00:00+00:00"},
// {name: 'abc', effectiveDate: "2016-05-01T00:00:00+00:00"},
// ];
答案 0 :(得分:4)
我相信你犯了一个简单的错误,你将ungroup设置为你的f函数,而它是你的g函数:
const ungroupAndFlatten = compose(flatten, ungroup)
切换取消组合并展平,一切都会正常工作
答案 1 :(得分:2)
函数compose
的评估顺序从从右到左。
/*
* 1. take x
* 2. execute g(x)
* 3. take the return value of g(x) and execute f with it
*/
const compose = (f, g) => x => f(g(x))
另一个名为pipe
的函数从从左到右评估
const pipe = (g, f) => x => f(g(x))
正如@Nima Hakimi已经提到的,你已经颠倒了参数顺序。
为了解决你的问题,我们可以
切换参数的顺序
const ungroupAndFlatten = compose( flatten, ungroup )
const compose = (f, g) => x =>
f(g(x))
const ungroup = obj =>
Object.keys(obj)
.map(x => obj[x]);
const flatten = arrs =>
arrs.reduce((acc, item) => acc.concat(item), [])
const groupedByName = {
abc: [
{ name: 'abc', effectiveDate: '2016-01-01T00:00:00+00:00' },
{ name: 'abc', effectiveDate: '2016-04-01T00:00:00+00:00' },
{ name: 'abc', effectiveDate: '2016-05-01T00:00:00+00:00' }
],
abcd: [
{ name: 'abcd', effectiveDate: '2016-02-01T00:00:00+00:00' },
{ name: 'abcd', effectiveDate: '2016-09-01T00:00:00+00:00' }
]
}
const ungroupAndFlatten = compose(
flatten,
ungroup
)
console.log(
ungroupAndFlatten(groupedByName)
)
或使用pipe
const ungroupAndFlatten = pipe( ungroup, flatten )
const pipe = (g, f) => x =>
f(g(x))
const ungroup = obj =>
Object.keys(obj)
.map(x => obj[x]);
const flatten = arrs =>
arrs.reduce((acc, item) => acc.concat(item), [])
const groupedByName = {
abc: [
{ name: 'abc', effectiveDate: '2016-01-01T00:00:00+00:00' },
{ name: 'abc', effectiveDate: '2016-04-01T00:00:00+00:00' },
{ name: 'abc', effectiveDate: '2016-05-01T00:00:00+00:00' }
],
abcd: [
{ name: 'abcd', effectiveDate: '2016-02-01T00:00:00+00:00' },
{ name: 'abcd', effectiveDate: '2016-09-01T00:00:00+00:00' }
]
}
const ungroupAndFlatten = pipe(
ungroup,
flatten
)
console.log(
ungroupAndFlatten(groupedByName)
)
n
参数的函数组合我们再次
const compose = (...fns) => fns.reduceRight((f, g) => (...args) => g(f(...args)))
const pipe = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)))
我们的目标是同时撰写ungroup
和flatten
函数groupBy
。
我们可以试试
const groupByNameAndFlattenAndUngroup = compose(
flatten,
ungroup,
groupBy('name', x) // <-- this is our problem
)
但这不起作用。我们只能用一个参数组合函数。解决方案是将groupBy
重写为 curried 版本:
const groupBy = xs => key =>
xs.reduce((rv, x) => {
(rv[x[key]] = rv[x[key]] || []).push(x)
return rv
}, {})
const groupByNameAndFlattenAndUngroup = (key, xs) => compose(
flatten,
ungroup,
groupBy ('name')
) (xs)
但是这个解决方案可以更短。如果我们将参数的顺序从groupBy
切换到groupBy = key => xs => {/*..*/}
,我们可以这样做:
const groupBy = key => xs =>
xs.reduce((rv, x) => {
(rv[x[key]] = rv[x[key]] || []).push(x)
return rv
}, {})
const groupByNameAndFlattenAndUngroup = compose(
flatten,
ungroup,
groupBy ('name')
)
const arrs = [
{name: 'abc', effectiveDate: "2016-01-01T00:00:00+00:00"},
{name: 'abcd', effectiveDate: "2016-02-01T00:00:00+00:00"},
{name: 'abcd', effectiveDate: "2016-09-01T00:00:00+00:00"},
{name: 'abc', effectiveDate: "2016-04-01T00:00:00+00:00"},
{name: 'abc', effectiveDate: "2016-05-01T00:00:00+00:00"},
]
const compose = (...fns) => fns.reduceRight((f, g) => (...args) =>
g(f(...args)))
const ungroup = obj =>
Object.keys(obj)
.map(x => obj[x]);
const flatten = arrs =>
arrs.reduce((acc, item) => acc.concat(item), [])
const groupBy = key => xs =>
xs.reduce((rv, x) => {
(rv[x[key]] = rv[x[key]] || []).push(x)
return rv
}, {})
const groupByName = groupBy ('name')
const groupByEffectiveDate = groupBy ('effectiveDate')
const groupByNameAndFlattenAndUngroup = compose(
flatten,
ungroup,
groupByName
)
const groupBygroupByEffectiveDateAndFlattenAndUngroup = compose(
flatten,
ungroup,
groupByEffectiveDate
)
console.log(
groupByNameAndFlattenAndUngroup (arrs)
)
console.log(
groupBygroupByEffectiveDateAndFlattenAndUngroup (arrs)
)
答案 2 :(得分:0)
您可以在单个函数中取消组合和展平。
const ungroupAndFlatten = (obj) => Object.keys(obj).reduce((a, k) => {obj[k].forEach(e => a.push(e)); return a}, [])