Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Averaging successive pairs of values in 2d array

I am trying to take the average of successive pairs of ints in a 2d array.

e.g. if the starting array looks like this:

[
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60]
];

The resulting array should look like:

[
  [1.5, 3.5, 5.5],
  [15, 35, 55]
]

My method is to loop through each array in turn, using %2 to select every other value, add them together and then push to a new 2d array.

Can anyone guide why the actual result is:

[
  [1.5, 3.5, 5.5, 15, 35, 55],
  [1.5, 3.5, 5.5, 15, 35, 55]
]

Here is my code:

var data = [
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60]
];

//create the same number of empty arrays as there are arrays in data.
var averagedCols = new Array(data.length).fill([]);

for (var i = 0; i < data.length; i++) {
  for(var j = 0; j < data[i].length; j++) {
    if (j%2 === 0) {
      var average = (data[i][j] + data[i][j+1])/2;
      averagedCols[i].push(average);
    } 
  }
}
console.log(averagedCols);

https://jsbin.com/rogemonave/edit?js,console

Note: jsbin also prints [circular object Array] when I try to print the whole resulting array, but a quick google seems to say this is a problem with jsbin not my code as this is not happening on my computer. Could still be an issue with my code though.

like image 248
jopfre Avatar asked Mar 05 '23 21:03

jopfre


1 Answers

The problem with your original code is that when you do .fill([]), you're filling with multiple references of the same empty array - there's only one empty array in memory, which each index of averagedCols refers to. You can fix this by explicitly creating the array on each iteration with Array.from:

var data = [
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60]
];

//create the same number of empty arrays as there are arrays in data.
var averagedCols = Array.from(
  { length: data.length },
  () => []
);

for (var i = 0; i < data.length; i++) {
  for(var j = 0; j < data[i].length; j++) {
    if (j%2 === 0) {
      var average = (data[i][j] + data[i][j+1])/2;
      averagedCols[i].push(average);
    } 
  }
}
console.log(averagedCols);

Best to only use .fill when filling an array with primitives - for non-primitives (objects, arrays, and functions), use Array.from instead.

The logic will probably be easier if you first chunk the array items into pairs, eg [1, 2, 3, 4, 5, 6] to [[1, 2], [3, 4], [5, 6]]. Then, all you need is a simple .map to average each pair:

function toPairs(arr) {
  const pairs = [];
  for (let i = 0; i < arr.length; i += 2) {
    pairs.push(arr.slice(i, i + 2));
  }
  return pairs;
}

const input = [
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60]
];
const output = input
  .map(toPairs)
  .map(arrayOfPairs => arrayOfPairs.map(pair => (pair[0] + pair[1]) / 2));
console.log(output);
like image 91
CertainPerformance Avatar answered Mar 16 '23 09:03

CertainPerformance