我能否使用array.prototype.reduce()来同时处理两个数组?

4

我有两个长度相同的数组,我想用reduce方法同时处理它们。类似于:

var arr1 = [2, 3, 4, 5, 6];
var arr2 = [5, 10, 4, 9, 5];
var productSum = arr1.reduce(function(sumOfProducts, item, secondArrayItem) {
    /* here I would like to multiply item from arr1 by the item from arr2 at the same index */
    return sumOfProducts + item * secondArrayItem;  
}, 0, arr2)
console.log(productSum);  // 131

当然,一种选择是使用currentIndexarr2中访问正确的项目,但这种解决方案很丑陋,因为我正在访问函数范围之外的变量。

我的具体用例是,我有一个资源数组,例如var resources = [2, 5, 4, 6, 2],我想检查每个项目是否高于另一个数组中相应的资源成本,例如var cost = [3, 1, 0, 0, 1]

是否有一些不错的解决方案可以使用reduce()函数?


2
通常可以通过将两个列表压缩在一起,然后减少压缩后的列表来完成此操作。但是我不知道如何在JS中以惯用方式压缩列表。 - Carcigenicate
4
“这个解决方案不太优雅,因为我在函数范围之外访问了一个变量。” - 我并不认为这有什么不好,我们经常在访问全局变量或使用闭包时这样做。重要的是该变量是常量。真正不好的是,a) 它不对称(访问 arr1 的方式与访问 arr2 不同),b) 我们没有确保数组具有相同的长度,所以我们不知道 arr2[i] 是否访问了有效的索引。 - Bergi
3个回答

2
使用Ramda,您可以首先将这两个列表压缩,然后对其进行缩减并使用解构来提取数组元素并将它们作为参数传递给回调函数:

const reduceTwo = (callback, initialValue, arr1, arr2) =>
  R.reduce((acc, [x, y]) => callback(acc, x, y), initialValue, R.zip(arr1, arr2));

const arr1 = [2, 3, 4, 5, 6];
const arr2 = [5, 10, 4, 9, 5];
console.log(reduceTwo((acc, x, y) => acc + x * y, 0, arr1, arr2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script>


4
仅为zip函数使用整个库对我来说有些多余... - BoltKey
2
@BoltKey 为什么?如果你使用webpack和tree shaking来打包你的代码,它不会对性能产生任何负面影响。 - Michał Perłakowski

1
我知道的标准做法是将这两个列表合并成一组对应的元素("压缩"),然后减少这些组合的列表。
var zipped = zip(arr1, arr2)

reduce((acc, [x, y]) => (Use x and y), 
              zipped) 

关于 zip 的实现,参见这个问题。

(我下班时会验证语法)


这种方法适用于大型数组吗?我不想在同时迭代两个数组的值时创建一个全新的数组。 - BoltKey
4
如果你想要处理大型数组,就应该放弃使用reduce而改用简单的for循环。 - Michał Perłakowski
1
@BoltKey,当处理惰性结构时,这是一个更好的方法,我承认。它将需要1次迭代来压缩,然后另一次来减少,并创建一个中间列表,因此很遗憾,这不会有良好的性能表现。 - Carcigenicate
@BoltKey 我同意Michal的观点(抱歉,我可能说错了名字)。通过使用一个简单的for循环来循环索引,您可以轻松地同时索引两个列表。这完全消除了任何中间列表和不必要的迭代的需要。有时候,老派的命令式方法是最好的。 - Carcigenicate

0

您可以使用纯JS按如下方式操作;

var arr1 = [2, 3, 4, 5, 6],
    arr2 = [5, 10, 4, 9, 5],
  result = arr1.reduce((r,c,i) => (r.sum = r.sum ? r.sum + c * r[i] : c * r[i], r), arr2.slice()).sum;
console.log(result);

为了不使用状态变量来改变它,我使用了.slice() arr2 ,但如果之后您不会应用for in循环到arr2或者其他的方式,您还是可以不使用切片。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接