Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/407.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 函数式编程:属性之和_Javascript_Functional Programming_Ramda.js - Fatal编程技术网

Javascript 函数式编程:属性之和

Javascript 函数式编程:属性之和,javascript,functional-programming,ramda.js,Javascript,Functional Programming,Ramda.js,我试图在JS中实现一个函数,它获取对象列表并返回特定属性的总和。例如 var l = [ {a: 1, b: 2, c: 0}, {a: 1, b: 3, c: -1}, {a: 1, b: 4, c: 0}, ] func(['a', 'b'], l) -> {a: 3, b: 9} 原则上,我需要这样一个函数: R.map(R.props($1, _), $2) fnOverProp(R.sum, 'b', list); //=> 9 fnOverProps(

我试图在JS中实现一个函数,它获取对象列表并返回特定属性的总和。例如

var l = [
  {a: 1, b: 2, c:  0},
  {a: 1, b: 3, c: -1},
  {a: 1, b: 4, c:  0},
]
func(['a', 'b'], l)
-> {a: 3, b: 9}
原则上,我需要这样一个函数:

R.map(R.props($1, _), $2)
fnOverProp(R.sum, 'b', list); //=> 9
fnOverProps(R.sum, ['a', 'b'], list); //=> {a: 3, b: 9}
const sumOverProps = fnOverProps(R.sum);
sumOverProps(['a', 'c'], list); //=> {a: 3, c: -1}
在函数式编程中实现这样的东西最优雅的方式是什么
R.map(R.props)
由于明显的原因不起作用。我尝试使用一些与
R.compose
R.pipe
的组合,但我运气不佳

您可以尝试以下方法:

function add(a, b){  
   return Object.keys(a).reduce(function(p, c){
     p[c] += a[c];
     return p;
   }, b);
}

console.log(R.reduce(add, {a:0, b:0, c:0}, l))
这是另一种方法:

R.pipe(R.map(R.props(['a', 'b', 'c'])), R.transpose, R.map(R.sum))(l);

我将把它分为两部分:

const fnOverProp = R.curry((fn, prop, list) => fn(R.pluck(prop, list)));

const fnOverProps = R.curry((fn, props, list) => 
    R.fromPairs(R.zip(props)(R.map(fnOverProp(fn, __, list), props))));
(对不起,我在这里对命名有一个创造性的障碍。这些名字太糟糕了。)

您可以这样使用它:

R.map(R.props($1, _), $2)
fnOverProp(R.sum, 'b', list); //=> 9
fnOverProps(R.sum, ['a', 'b'], list); //=> {a: 3, b: 9}
const sumOverProps = fnOverProps(R.sum);
sumOverProps(['a', 'c'], list); //=> {a: 3, c: -1}
首先请注意,我概括了您的想法,将
sum
作为一个参数。这对我来说很有意义,这并不是一个人想要用这样一个函数做的唯一事情

然后我将其分解为一个函数,该函数对单个属性名进行操作。我觉得这本身就很有用。您可能不需要对整个列表执行此操作,并且此函数本身值得使用

然后我将其封装在一个函数中,该函数将第一个函数映射到一个属性列表上。请注意,这实际上是一个相当简单的函数:

(fn, props, list) => R.map(fnOverProp(fn, R.__, list), props)
包装在两个包装器中,将结果的平面列表转换为您要查找的对象输出
R.zip(props)(,props)
[3,-1]
转换为
['a',3],'c',-1]
,然后
R.fromPairs
将其转换为
{a:3,c:-1}

这并没有为您提供您想要的单行实现。显然,你可以把第一个函数的定义折叠成第二个,但我认为这并不能给你带来什么好处。即使它可以免费发表,我也希望这会降低这种情况下的可读性

const func = (props, objs) =>
  reduce(useWith(mergeWith(add), [identity, pick(props)]), pick(props, map(flip(objOf)(0), props)), objs)

您可以在

中看到这一点。这也可以定义为对象列表上的缩减器。给定结果的一些初始状态,我们需要一个函数,可以对两个对象属性的结果求和,其中
props
是我们感兴趣的属性列表:

reduce(useWith(mergeWith(add, [identity, pick(props)]))
然后,对于列表是否可能为非空,或者是否保证至少有一个对象,您有两个选项。如果列表保证为非空,则reducer的初始值可以是列表的头部,尾部作为要迭代的列表

const func = (props, objs) =>
  reduce(useWith(mergeWith(add), [identity, pick(props)]), pick(props, head(objs)), tail(objs))
但是,如果列表可能为空,则必须使用空值初始化
reduce
函数(在这种情况下为零)


b
prop不应该等于9吗?你完全正确!对不起,我修好了。这确实是一个正确的解决方案,但它不是很优雅。理想情况下,我正在寻找一条表示我要计算的内容的直线。此外,我还想将解决方案应用于类似情况下可能出现的其他问题。第二种方法用单行表示,希望这能有所帮助。谢谢,我正在寻找类似
R.pipe(R.map(R.props),R.transpose,R.map(R.sum))(['a','b','c'],l)
。使类似这样的东西起作用的诀窍实际上是函数式编程中的概念,我还不了解。啊,
R.useWith
看起来非常有用。我快到了:
R.pipe(R.useWith(R.map,[R.props,R.identity]),R.transpose,R.map(R.sum))(['a','b'],[{a:1,b:2},{a:2,b:2}])