Reducing array to average readings Taking the payload below, I need to output the average of each reading.

For example the readings for key 2 are 1, 4, 7.  The average is (1+4+7)/3 = 4.

The data is formatted in multi-dimensional arrays, such that each sub-array contains pairs with a key and a reading value. For example:

[
  [
    [2, 1],
    [4, 2],
    [6, 3]
  ],
  [
    [2, 4],
    [4, 5],
    [6, 6]
  ],
  [
    [2, 7],
    [4, 8],
    [6, 9]
  ]
]


The final result should be: 

[
[2, 4],
[4, 5],
[6, 6]
] 


My effort so far seems to work.

const payload = [
  [
    [2, 1],
    [4, 2],
    [6, 3]
  ],
  [
    [2, 4],
    [4, 5],
    [6, 6]
  ],
  [
    [2, 7],
    [4, 8],
    [6, 9]
  ]
]

const result = payload.reduce((accumulator, currentValue, currentIndex, array) =&gt; {

    if(currentIndex === 0){
        return accumulator
    }
    return currentValue.reduce((a, c, i) =&gt; {       
        accumulator[i][1] += c[1]
        return accumulator
    }, accumulator)

 }).map((currentValue, index, array) =&gt; {
    return [currentValue[0], currentValue[1] / array.length]
})
Average calculation issue

The example data happens to be a 3x3 matrix of values, so the calculation of the average appears to be correct. However, try using a 2x3 matrix of values (i.e. remove the 3rd sub-array of values) - it should become clear that the divisor used in the calculation of the average is incorrect. 

One should divide the sum by the number of readings corresponding to each key, not the number of keys in each sub-array- i.e. divide by payload.length instead of array.length in the callback to Array.map().

Original Array Modification

le_m is correct with the statement in the comment:


  Above payload.reduce(...) mutates the first element of payload - that is probably unexpected behavior and could cause bugs further on.


This is because the initialValue parameter of Array.reduce() is omitted, which causes payload[0] to be used as accumulator the first time 1. This can be observed by inspecting the values of currentIndex in the callback - for the sample data, it starts with 1 and ends with 2.

In order to not mutate the first element of payload, a deep clone of the first element can be used (e.g. with JSON.parse() and JSON.stringify()).

let initialValue = [];
if (payload.length) {
    initialValue = JSON.parse(JSON.stringify(payload[0]));
}
const result = payload.reduce((accumulator, currentValue, currentIndex) =&gt; { 
    /*...*/ 
}, initialValue)).map((currentValue, index, array) =&gt; {
    return [currentValue[0], currentValue[1] / array.length]
});




1https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Parameters