Javascript 中的多维数组累加和
Multi dimensional array cumulative sum in Javascript
给定一个多维数组:
var a = [[3,2,5], [4,1,7], [1,6,8]];
我想对每个数组进行累加和 return 以下结果:
[[3,2,5], [7,3,12], [8,9,20]];
- 每个子数组第一个元素的总和:3 4 1
- 每个子数组的第二个元素的总和:2 1 6
- 每个子数组的第 3 个元素求和:5 7 8
我试过使用 reduce(),但不能完全得到预期的结果。
任何建议,非常感谢。
S
更新 -
更上一层楼:
var a = [
[new Date(), 3,2,5],
[new Date(), null,1,7],
[new Date(), null,6,8],
[new Date(), 1,2,3]
];
应该导致:
[[new Date(), 3,2,5],
[new Date(), null,3,12],
[new Date(), null,9,20],
[new Date(), 4,11,23]]
我的方法是创建一个多维 offsetIndex 数组:
var offsetIdx = [];
for (var i=1; i<a.length; i++) {
for (var z=0; z<a[i].length; z++) {
var zValue = a[i][z];
oIdx = offsetIdx[z] || 0;
a[i][z] = zValue && z!==0 ? a[i-1-oIdx][z] + zValue : zValue;
if(!zValue){
offsetIdx[z] = oIdx + 1;
} else {
offsetIdx[z] = 0;
}
}
}
很高兴看到其他使其超轻的方法。
for (var i=1; i<a.length; i++) {
for (var z=0; z<a[i].length; z++) {
a[i][z] = a[i-1]][z] + a[i][z]
}
}
数组应该在循环运行时动态更新。
这是破坏性的,所以它会修改原来的数组。
这将为您提供所有元素的总和。不完全是你问的,但我会在这里留下这个答案,以供将来抓住问题标题的访问者使用。
- Flatten first using your favorite library(下划线和lodash都有)
然后减少+求和。
_.flatten([1, [2, [3, [4]], 5]]);
// → [1, 2, [3, [4]], 5]
function cumulativeSum(arr) {
var result = [arr[0]];
for(var i = 1; i < arr.length; i++) {
result.push([]);
for(var j = 0; j < arr[0].length; j++) {
result[i].push(result[i - 1][j] + arr[i][j]);
}
}
return result;
}
document.body.innerHTML = JSON.stringify(cumulativeSum(
[[3,2,5], [4,1,7], [1,6,8]]
))
与其他答案不同,这个答案不是破坏性的,保留原始数组并返回结果。
好数学题。
为什么不先转置数组呢?关于这个问题的回答 - Transposing a 2D-array in JavaScript - suggests the underscore.js 解决方案:
_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
做到这一点。方法很多。
那么求和应该容易得多 - 只需 .map(f)
其中 f
是一个数组函数的求和。
IMO 这是一个很好且可读的解决方案,因为 "transpose+sum" 非常符合问题的列和性质,我会避免模糊这一点的命令式或循环繁重的解决方案。
使用Array.reduce
,看起来像这样
var arr = [[3,2,5], [4,1,7], [1,6,8]];
var arr2 = arr.reduce(function(a,b) {
var nested = Array.isArray(a[0]);
b = b.map(function(x,i) {
return x + (nested ? a[a.length-1] : a)[i];
});
if ( nested ) a.push(b);
return nested ? a : [a,b];
});
document.body.innerHTML = '<pre>' + JSON.stringify(arr2, 0, 4) + '</pre>';
这里有一个稍微 "optimized" (golfed) 的版本,传入一个减少和切片数组的起点
var arr = [[3,2,5], [4,1,7], [1,6,8]];
var arr2 = arr.slice(1).reduce(function(a,b) {
return [a.push(b.map(function(x,i) {return x+a[a.length-1][i]})), a].pop();
},[arr[0]]);
document.body.innerHTML = '<pre>' + JSON.stringify(arr2, 0, 4) + '</pre>';
使用 ES2015 使其成为单行
var arr = [[3,2,5], [4,1,7], [1,6,8]];
var a2 = arr.slice(1).reduce((a,b)=>[a,a.push(b.map((x,i)=>x+a[a.length-1][i]))][0],[arr[0]]);
document.body.innerHTML = '<pre>' + JSON.stringify(a2, 0, 4) + '</pre>';
给定一个多维数组:
var a = [[3,2,5], [4,1,7], [1,6,8]];
我想对每个数组进行累加和 return 以下结果:
[[3,2,5], [7,3,12], [8,9,20]];
- 每个子数组第一个元素的总和:3 4 1
- 每个子数组的第二个元素的总和:2 1 6
- 每个子数组的第 3 个元素求和:5 7 8
我试过使用 reduce(),但不能完全得到预期的结果。
任何建议,非常感谢。
S
更新 - 更上一层楼:
var a = [
[new Date(), 3,2,5],
[new Date(), null,1,7],
[new Date(), null,6,8],
[new Date(), 1,2,3]
];
应该导致:
[[new Date(), 3,2,5],
[new Date(), null,3,12],
[new Date(), null,9,20],
[new Date(), 4,11,23]]
我的方法是创建一个多维 offsetIndex 数组:
var offsetIdx = [];
for (var i=1; i<a.length; i++) {
for (var z=0; z<a[i].length; z++) {
var zValue = a[i][z];
oIdx = offsetIdx[z] || 0;
a[i][z] = zValue && z!==0 ? a[i-1-oIdx][z] + zValue : zValue;
if(!zValue){
offsetIdx[z] = oIdx + 1;
} else {
offsetIdx[z] = 0;
}
}
}
很高兴看到其他使其超轻的方法。
for (var i=1; i<a.length; i++) {
for (var z=0; z<a[i].length; z++) {
a[i][z] = a[i-1]][z] + a[i][z]
}
}
数组应该在循环运行时动态更新。 这是破坏性的,所以它会修改原来的数组。
这将为您提供所有元素的总和。不完全是你问的,但我会在这里留下这个答案,以供将来抓住问题标题的访问者使用。
- Flatten first using your favorite library(下划线和lodash都有)
然后减少+求和。
_.flatten([1, [2, [3, [4]], 5]]); // → [1, 2, [3, [4]], 5]
function cumulativeSum(arr) {
var result = [arr[0]];
for(var i = 1; i < arr.length; i++) {
result.push([]);
for(var j = 0; j < arr[0].length; j++) {
result[i].push(result[i - 1][j] + arr[i][j]);
}
}
return result;
}
document.body.innerHTML = JSON.stringify(cumulativeSum(
[[3,2,5], [4,1,7], [1,6,8]]
))
与其他答案不同,这个答案不是破坏性的,保留原始数组并返回结果。
好数学题。
为什么不先转置数组呢?关于这个问题的回答 - Transposing a 2D-array in JavaScript - suggests the underscore.js 解决方案:
_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
做到这一点。方法很多。
那么求和应该容易得多 - 只需 .map(f)
其中 f
是一个数组函数的求和。
IMO 这是一个很好且可读的解决方案,因为 "transpose+sum" 非常符合问题的列和性质,我会避免模糊这一点的命令式或循环繁重的解决方案。
使用Array.reduce
,看起来像这样
var arr = [[3,2,5], [4,1,7], [1,6,8]];
var arr2 = arr.reduce(function(a,b) {
var nested = Array.isArray(a[0]);
b = b.map(function(x,i) {
return x + (nested ? a[a.length-1] : a)[i];
});
if ( nested ) a.push(b);
return nested ? a : [a,b];
});
document.body.innerHTML = '<pre>' + JSON.stringify(arr2, 0, 4) + '</pre>';
这里有一个稍微 "optimized" (golfed) 的版本,传入一个减少和切片数组的起点
var arr = [[3,2,5], [4,1,7], [1,6,8]];
var arr2 = arr.slice(1).reduce(function(a,b) {
return [a.push(b.map(function(x,i) {return x+a[a.length-1][i]})), a].pop();
},[arr[0]]);
document.body.innerHTML = '<pre>' + JSON.stringify(arr2, 0, 4) + '</pre>';
使用 ES2015 使其成为单行
var arr = [[3,2,5], [4,1,7], [1,6,8]];
var a2 = arr.slice(1).reduce((a,b)=>[a,a.push(b.map((x,i)=>x+a[a.length-1][i]))][0],[arr[0]]);
document.body.innerHTML = '<pre>' + JSON.stringify(a2, 0, 4) + '</pre>';