1

I have an array that looks like this:

var array = [ [1,3,9],
              [4,6,8],
              [3,7,5],
              [2,8,4] ];

I want to get the average number of each column, but for now I was just trying to sum them. This is my code:

var sum = function(arr) {
  return arr.reduce(function(a, b) { return a + b; }, 0);
};

var tests = array.map(function(v, i) {
  return sum(array.map(function(v) { return v[i]; }))
});

return tests;

The output turns the sum correctly, but it seems to be doing as many sums as there are rows (4 rows), instead of 3 corresponding to the columns. This is the output:

tests = [10, 24, 26, NULL]

Any idea why is this happening? How can I perform the calculation only for as many columns as there are instead of rows?

EDIT:

I'm using Nenad's answer which gives the correct result. But I need to implement it on Google Sheets's Script Editor, which doesn't seem to understand the shortened functions with "=>". I replaced the shortened pieces for the longer version, but I'm not getting the same result.

var array = [ [1,3,9],
              [4,6,8],
              [3,7,5],
              [2,8,4] ];

var sums = array.reduce(function(r, e, i) {
    e.forEach(function(a,j) { r[j] = (r[j] || 0) + a;
                             if (i == array.length-1) { r = r.map(function(el){ return el/array.length; }); }
                            });
    return r;
  }, [])
  
console.log(sums);  

I don't see any difference between this and the shortened version, yet this one returns:

sums = [0.15625, 0.75, 1.34375];

Instead of:

sums = [2.5, 6, 6.5];

The sum is done correctly, but when I divide "el/array.length" or even "el/4", the result are these 3 weird numbers. I don't understand where are those coming from. Where did I go wrong?

6 Answers 6

2

You can use reduce() and forEach() to return result.

var array = [
  [1, 3, 9],
  [4, 6, 8],
  [3, 7, 5],
  [2, 8, 4]
];

var sums = array.reduce(function(r, e, i) {
  e.forEach((a, j) => r[j] = (r[j] || 0) + a)
  return r;
}, [])

console.log(sums)

To calculate avg for each column you can add map() on last iteration of array.

var array = [
  [1, 3, 9],
  [4, 6, 8],
  [3, 7, 5],
  [2, 8, 4]
];

var sums = array.reduce(function(r, e, i) {
  e.forEach((a, j) => r[j] = (r[j] || 0) + a)
  if (i == array.length - 1) r = r.map(el => el / array.length);
  return r;
}, [])

console.log(sums)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much Nenad! This other version does work on Google's Script Editor. I messed up a great deal with some parenthesis -_- This whole .map/.reduce functions are very new to me. Thanks again, Nenad!
1

To get the average of each column you'd first have to know the amount of columns. Then grab each column with map() and to sum everything with reduce()

Now we have the column, the sum and then just divide by column length.

const arrayColumn = (a, n) => a.map(x => x[n]);
const arraySum    = (a) => a.reduce((b,c) => b + c);

var arr = [ 
 [1,3,9],
 [4,6,8],
 [3,7,5],
 [2,8,4] 
];

for(i=0; i<arr[0].length; i++){
  console.log(arraySum((col = arrayColumn(arr, i))) / col.length);
}

Comments

1

This will convert the 2d array of rows into a 2d array of columns and then maps each inner array of columns to an average. There is a little bit of boilerplate to make the inner reduce immutable you could use lodash/fp or another library to clean this up.

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

const averageColumns = array => array.reduce((acc, row) => {
  return row.reduce((accRow, col, index) => {
    const cols = accRow[index] || [];
    return [...accRow.slice(0, index), cols.concat(col), ...accRow.slice(index + 1)];

  }, acc);
}, []).map(avg);

const avg = array => array.reduce((acc, next) => acc + next, 0) / array.length;

console.log(averageColumns(array));

Comments

0

map() + reduce() solution

var array = [ [1,3,9], [4,6,8], [3,7,5], [2,8,4] ];


array.map(function(item, i, arr) {
	arr[i] = item.reduce((a, b) => a + b, 0) / 2;
  	console.log(arr[i])
});

I'm a little fix up your code
you have mistake here return sum(array.map(function(v) { return v[i]; }))

var array = [ [1,3,9],
              [4,6,8],
              [3,7,5],
              [2,8,4] ];
function sum(arr) {
  return arr.reduce(function(a, b) { return a + b; }, 0);
};

var tests = array.map(function(v, i, arr) {
  return sum(arr[i])
});

tests;

Comments

0

You can transpose the array of arrays,
popular utility libraries (ramda for ex) have a transpose implementation,
but it's easy to implement your own:

const trans = arr => arr[0].map((_,i) => arr.map(x => x[i]))

var array = [ 
 [1,3,9],
 [4,6,8],
 [3,7,5],
 [2,8,4] 
];
const res = trans(array)
console.log(res)


// to get the sum you can use reduce
console.log(res.map( x => x.reduce((a,b) => a + b )))

Comments

0

I would do as follows;

var array = [ [1,3,9],
              [4,6,8],
              [3,7,5],
              [2,8,4] ];
   result = array.map(a => a.reduce((p,c,_,a) => p + c/a.length,0));
console.log(result);

As per the comments... Yes they are right, the right solution should be through a switch of the .map() and .reduce();

var array = [ [1,3,9],
              [4,6,8],
              [3,7,5],
              [2,8,4] ],
   result = array.reduce((p,c) => p.map((n,i) => n + c[i]/array.length), Array(array[0].length).fill(0));
console.log(result);

1 Comment

The sum of a column is requested, not the sum of an index.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.