如何将数组中相同索引的元素相加成一个单独的数组?

24

假设我有一个数组的数组,就像这样:

[
  [0, 1, 3],
  [2, 4, 6],
  [5, 5, 7],
  [10, 0, 3]
]

在javascript中,如何生成一个新的数组,该数组将内部数组每个位置的所有值相加? 在这种情况下,结果将是:[17, 10, 19]。我需要能够拥有适用于内部数组长度的解决方案。我认为可以使用map和for-of的某些组合,或可能是reduce,但我无法完全理解它。我已经搜索过了,但找不到与此完全匹配的示例。


如果一些子数组长度不同,您希望做什么? 您希望将其视为错误吗?还是只需对于与更长的数组不匹配的较短的数组中的数组元素使用0 - jfriend00
@jfriend00 这是一个好问题。如果可以选择的话,我会建议在较短的数组中使用0。 - hmlee
7个回答

54
你可以使用 Array.prototype.reduce()Array.prototype.forEach() 结合使用。

var array = [
        [0, 1, 3],
        [2, 4, 6],
        [5, 5, 7],
        [10, 0, 3]
    ],
    result = array.reduce(function (r, a) {
        a.forEach(function (b, i) {
            r[i] = (r[i] || 0) + b;
        });
        return r;
    }, []);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

通过使用一个映射来缩短数组,可以更新更简洁的方法。

var array = [[0, 1, 3], [2, 4, 6], [5, 5, 7], [10, 0, 3]],
    result = array.reduce((r, a) => a.map((b, i) => (r[i] || 0) + b), []);
    
console.log(result);


12

使用Lodash 4

function sum_columns(data) {
  return _.map(_.unzip(data), _.sum);
}

var result = sum_columns([
  [1, 2],
  [4, 8, 16],
  [32]
]);

console.log(JSON.stringify(result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

关于旧版Lodash和一些备注

Lodash 4已经改变了_.unzipWith的工作方式,现在迭代器一次性获取传递的所有值,因此我们不能再使用缩减器样式的_.add。在Lodash 3中,以下示例可以正常工作:

function sum_columns(data) {
  return _.unzipWith(data, _.add);
}

var result = sum_columns([
  [1, 2],
  [4, 8, 16],
  [32],
]);

console.log(JSON.stringify(result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>

_.unzipWith会在某行比其他行短的情况下插入undefined,而_.sum将未定义的值作为0处理。(自Lodash 3起)

如果您的输入数据可能包含undefinednull项,并且希望将它们视为0,则可以使用此选项:

function sum_columns_safe(data) {
  return _.map(_.unzip(data), _.sum);
}

function sum_columns(data) {
  return _.unzipWith(data, _.add);
}

console.log(sum_columns_safe([[undefined]])); // [0]
console.log(sum_columns([[undefined]]));      // [undefined]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>

这段代码适用于 Lodash 3 版本,不幸的是在 Lodash 4 中,我没有找到一种好的方式将 undefined 视为 0 进行处理,因为现在 sum 已经被更改了,所以 _.sum([undefined]) === undefined


谢谢。我对lodash不是很熟悉,但看起来我应该更多地了解它。看文档,他们有一个例子使用_.unzipWith和_.add,像:return _.unzipWith(data, _.add)。那也可以吗? - hmlee
Lodash 没有 flatten() 吗? - binki
@hmlee 是的,那样更好。唯一的区别是 _.map(_.unzip([[undefined]]), _.sum) -> [0],但是 _.unzipWith([[undefined]], _.add) === [undefined] - Tamas Hegedus
@binki,它确实有用,但在这种情况下没有帮助。 - Tamas Hegedus
嗨@TamasHegedus!在lodash 4.17.11中,我得到了不同的结果[5,10,16],而不是[37,10,16] - Penny Liu
显示剩余4条评论

5

使用 ES6 中的一行代码,结合 mapreduce

var a = [ [0, 1, 3], [2, 4, 6], [5, 5, 7], [10, 0, 3] ];

var sum = a[0].map((_, i) => a.reduce((p, _, j) => p + a[j][i], 0));

document.write(sum);


0
假设嵌套数组的长度总是相同的,那么可以使用concat和reduce。

    function totalIt (arr) {
        var lng = arr[0].length;
       return [].concat.apply([],arr)  //flatten the array
                .reduce( function(arr, val, ind){ //loop over and create a new array
                    var i = ind%lng;  //get the column
                    arr[i] = (arr[i] || 0) + val; //update total for column
                    return arr;  //return the updated array
                }, []);  //the new array used by reduce
    }
    
    var arr = [
      [0, 1, 3],
      [2, 4, 6],
      [5, 5, 7],
      [10, 0, 3]
    ];
    console.log(totalIt(arr));  //[17, 10, 19]


0
假设数组是静态的,就像操作符所展示的那样。

a = [
      [0, 1, 3],
      [2, 4, 6],
      [5, 5, 7],
      [10, 0, 3]
    ]

b = []
      
for(i = 0; i < a[0].length; i++){      
  count = 0
  for(j = 0; j < a.length; j++){    
     count += a[j][i]   
   }
   b.push(count)
}  
console.log(b)


0

到目前为止,还没有使用问题中提到的for ... of得到答案。
我已经使用了条件语句来处理不同长度的内部数组。

var a = [
  [0, 1, 3],
  [2, 4, 6],
  [5, 5, 7],
  [10, 0, 3]
];
i = 0;
r = []
for (const inner of a) {
  j = 0;
  for (const num of inner) {
    if (j == r.length) r.push(num)
    else r[j] += num
    j++;
  }
  i++;
}
console.log(r);

在这种情况下,经典的for循环比for ... of更适合。
以下代码片段使用条件(三元)运算符。

var a = [
  [0, 1, 3],
  [2, 4, 6],
  [5, 5, 7],
  [10, 0, 3]
];

r = [];
for (i = 0; i < a.length; i++) {
  for (j = 0; j < a[i].length; j++) {
    j==r.length ? r.push(a[i][j]) : r[j]+=a[i][j]
  }
}

console.log(r);

使用映射和归约的解决方案,将来自不同长度数组的元素相加。

var array = [
  [0],
  [2, 4],
  [5, 5, 7, 10, 20, 30],
  [10, 0]
];
b = Array(array.reduce((a, b) => Math.max(a, b.length), 0)).fill(0);
result = array.reduce((r, a) => b.map((_, i) => (a[i] || 0) + (r[i] || 0)), []);

console.log(result);


-2
const ar = [
  [0, 1, 3],
  [2, 4, 6],
  [5, 5, 7],
  [10, 0, 3]
]   

ar.map( item => item.reduce( (memo, value)=> memo+= value, 0 ) )
//result-> [4, 12, 17, 13]

虽然这段代码可能回答了问题,但是提供关于为什么和/或如何回答问题的额外上下文可以提高其长期价值。 - Donald Duck
这并没有回答问题,它对每个数组求和。 - JJP

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