How can I sum vertically all data from an array of arrays?
arrayOfArrays = [{
label: 'First Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Second Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Third Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
}
];
var result = arrayOfArrays.reduce(function(array1, array2) {
return array1.data.map(function(value, index) {
return value + array2.data[index];
}, 0);
});
console.log(result)
How can I sum vertically all data from an array of arrays?
arrayOfArrays = [{
label: 'First Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Second Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Third Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
}
];
var result = arrayOfArrays.reduce(function(array1, array2) {
return array1.data.map(function(value, index) {
return value + array2.data[index];
}, 0);
});
console.log(result)
The output should be the vertical sum of arrays. [3,6,9,12,15,18,21,24]
The problem is that array1 return always as undefined.
Share Improve this question edited Aug 26, 2019 at 10:35 Rajesh 25k5 gold badges50 silver badges83 bronze badges asked Aug 26, 2019 at 10:29 Irimescu CosminIrimescu Cosmin 1308 bronze badges7 Answers
Reset to default 3You code is almost correct but with 1 issues.
You are looping on accumulator. This will be an array of number in second iteration. Instead loop over array2
or current item.
Idea of .reduce
is to have same signature for all iteration. If you do not pass default value for accumulator, first iteration will be of type Array<{ label: string, data: Array<number>}>
and second iteration will be just Array<number>
. So you can skip behavior for first iteration by passing default value as []
. Now the calculation will break as array[n]
will be undefined
. For this, you can use a default value of 0
.
So your calculation will look like:
value + (array1[index] || 0)
Following is a sample:
arrayOfArrays = [{
label: 'First Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Second Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Third Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
}
];
var result = arrayOfArrays.reduce(function(array1, array2) {
return array2.data.map(function(value, index) {
return value + (array1[index] || 0);
}, 0);
}, []);
console.log(result)
Use the index/key
of map
and add to the previous value.
const arrayOfArrays = [{label:'First Value', data:[1,2,3,4,5,6,7,8]},{label:'Second Value', data:[1,2,3,4,5,6,7,8]},{label:'Third Value', data:[1,2,3,4,5,6,7,8]}];
const res = arrayOfArrays.reduce((acc, cur) => (cur.data.map((i, k) => {acc[k] = acc[k] ? acc[k] += i : i}), acc), [])
console.log(res)
you're using reduce in a wrong way, but heres a for loop that does the same job:
arrayOfArrays = [{
label:'First Value', data:[1,2,3,4,5,6,7,8]},{
label:'Second Value', data:[1,2,3,4,5,6,7,8]},{
label:'Third Value', data:[1,2,3,4,5,6,7,8]
}];
const newArr = [];
for(let x = 0; x < arrayOfArrays[0].length; x++){
newArr.push(arrayOfArrays[0].data[x]+arrayOfArrays[1].data[x]+arrayOfArrays[2].data[x])
}
console.log(newArr); // new array
You can flatten the array by looping the array of objects and pushing the data property to a new array, then use reduce/map on the flattened data:
arrayOfArrays = [
{label:'First Value', data:[1,2,3,4,5,6,7,8]},
{label:'Second Value', data:[1,2,3,4,5,6,7,8]},
{label:'Third Value', data:[1,2,3,4,5,6,7,8]}
];
var data = [];
arrayOfArrays.forEach((element)=> {
data.push(element.data)
})
var sum = (r, a) => r.map((b, i) => a[i] + b);
var result = data.reduce(sum);
console.log(result);
Which outputs:
[3, 6, 9, 12, 15, 18, 21, 24]
Working fiddle
If you know that the length of each array is same. you can do as follows
arrayOfArrays = [{
label: 'First Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Second Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Third Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
}
];
let out = arrayOfArrays.reduce((acc, {data}) => acc.map((e, i) => e+data[i]), new Array(8).fill(0));
console.log(out)
You are passing the wrong accumulator which should be an array also in wrong place, it must be with reduce
not with map
var result = arrayOfArrays.reduce(function (array1, array2) {
return array1.map(function (value, index) {
return value + array2.data[index];
});
}, Array(8).fill(0));
I would do it like this:
Introduce a helper
transport
function:const transport = (arr) => arr[0].map((col, i) => arr.map(row => row[i]));
Get a proper matrix:
const matrix = arrayOfArrays.map(el => el.data)
Then the task bees trivial:
const res = transport(matrix).map(arr => arr.reduce((x, y) => x + y)) // > (8) [3, 6, 9, 12, 15, 18, 21, 24]
You could take advantage of function generators in case you need to later transform or alterate the values, or just iterate them without needing the entire result set.
In this solution, a function generator is used and the logic applied is:
- Get the array with the longest length (assuming length might change)
- Get all the elements at index
i
from0
tolongest length
and yield their sum.
arrayOfArrays = [{
label: 'First Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Second Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
},
{
label: 'Third Value',
data: [1, 2, 3, 4, 5, 6, 7, 8]
}
];
/**
Sums elements of arrays inside the array vertically.
*/
function* sumVertically(arr) {
// Get the longest array.
const longestArrayLength = arr.sort(({length: l1}, {length: l2}) => l1 - l2)[0].length;
// Acquire all elements at index [i] of each array and sum them. Yield the sum.
for (let i = 0; i < longestArrayLength; i++) yield arr.map(e => e[i]).reduce((a,b) => a + b, 0);
}
const result = [...sumVertically(arrayOfArrays.map(i => i.data))];
console.log(result);