如何使用Ramda通过索引对n个数组求和

时间:2015-11-18 03:39:05

标签: javascript arrays functional-programming ramda.js

我一直在学习Ramda,并想知道如何通过索引来总结 n - 阵列。以下是我用2个数组做的事情。如何使这种方法扩展?

即。我希望能够这样做:sumByIndex( arr1, arr2, ..., arrn )

鉴于列表xy,结果数组应该产生[x0 + y0, x1 + y1, ..., xn + yn]。因此,对于 n-array 的情况,结果数组应为[ a[0][0] + a[1][0] + ... a[n][0], a[0][1] + a[1][1] + ... a[n][1], ..., a[0][n] + a[1][n] + ... + a[n][n] ],其中a[n]是一个数组作为位置n的参数。

var array1 = [1,2,3];
var array2 = [2,4,6];

var sumByIndex = R.map(R.sum);
var result = sumByIndex(R.zip(array1, array2));

$('pre').text(JSON.stringify(result, true));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.18.0/ramda.min.js"></script>
<pre></pre>

3 个答案:

答案 0 :(得分:1)

为实现这一目标,我们首先要创建一些通用的辅助函数:

// a new version of `map` that includes the index of each item
var mapI = R.addIndex(R.map);

// a function that can summarise a list of lists by their respective indices
var zipNReduce = R.curry(function(fn, lists) {
  return mapIndexed(function (_, n) {
    return fn(R.pluck(n, lists));
  }, R.head(lists));
});

获得这些内容后,我们可以通过将sumByIndex传递给上面定义的R.sum来创建zipNReduce

var sumByIndex = zipNReduce(R.sum);
sumByIndex([[1, 2, 3], [4, 5, 6], [7, 8, 9]]); // [12, 15, 18]

如果你更喜欢创建一个接受不同数量的数组作为参数而不是数组数组的函数,你只需用R.unapply包裹它:

var sumByIndex_ = R.unapply(sumByIndex);
sumByIndex_([1, 2, 3], [4, 5, 6], [7, 8, 9]); // [12, 15, 18]

如果您可能正在处理不同大小的列表,我们可以将R.sum换成略有变化,默认未定义值为零:

var sumDefaultZero = R.reduce(R.useWith(R.add, [R.identity, R.defaultTo(0)]), 0);
var sumByIndexSafe = zipNReduce(sumDefaultZero);
sumByIndexSafe([[1, 2, 3], [], [7, 9]]); // [8, 11, 3]

答案 1 :(得分:1)

我发现答案有点冗长。更好地保持简单。

import { compose, map, unnest, zip, sum } from 'ramda';

const a = [1,2,3]
const b = [4,5,6]
const c = [7,8,9]

function groupByIndex(/*[1,2,4], [4,5,6], ...*/) {
  return [...arguments].reduce(compose(map(unnest), zip));
}

const sumByIndex = map(sum);
const res = sumByIndex(groupByIndex(a,b,c))
// => [12,15,18]

答案 2 :(得分:0)

我来晚了一点,但是假设所有数组的长度相同,我们可以将第一个数组作为归约函数的初始值。其余部分通过zipWith函数进行迭代,该函数将两个数字相加。

const {unapply, converge, reduce, zipWith, add, head, tail} = R;

const a = [1,2,3];
const b = [4,5,6];
const c = [7,8,9];

var zipSum = 
  unapply(
    converge(
      reduce(zipWith(add)), [
        head,
        tail]));


var res = zipSum(a, b, c);

console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>