最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Sum array of arrays (matrix) vertically - Stack Overflow

programmeradmin1浏览0评论

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 badges
Add a ment  | 

7 Answers 7

Reset to default 3

You 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:

  1. Introduce a helper transport function:

    const transport = (arr) => arr[0].map((col, i) => arr.map(row => row[i]));
    
  2. Get a proper matrix:

    const matrix = arrayOfArrays.map(el => el.data)
    
  3. 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 from 0 to longest 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);

发布评论

评论列表(0)

  1. 暂无评论