Karan Singh Dhir
Karan Singh Dhir

Reputation: 751

Averaging out corresponding index value of arrays considering their lengths

I have a multidimensional array which contains arrays of different lengths. I want to average the corresponding index values of all the arrays. For arrays that don't have the index won't be considered when averaging the values.

var multiArray = [
  [4, 1, 3],
  [6, 4, 2, 3, 4],
  [8, 6, 1, 2],
  [2, 3]
];

var avgIdxArray = [];

// logic helper
// (4 + 6 + 8 + 2) / 4 = 5
// (1 + 4 + 6 + 3) / 4 = 3.5
// (3+ 2 +1) / 3 = 2
// (3 + 2) / 5 = 2.5
// 4 / 1 = 4;

// (sum of index values) / number of arrays that have those index

// desired output
console.log(avgIdxArray);
// [5, 3.5 ,2 ,2.5 ,4]

Can it be achieved using the .map(), .filter() and .reduce() method? Also what could be the most efficient way of handling this problem?

Upvotes: 0

Views: 70

Answers (3)

smellerbee
smellerbee

Reputation: 1913

Pure mapreduce.

Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0]).
map( x => Object.keys(multiArray).
map(y => x < multiArray[y].length?multiArray[y][x]:undefined)).
map( a => ({sum: (a.reduce((l,r) => (l?l:0) + (r?r:0))), length: (a.filter(x => x).length)}) ).
map( pair => pair.sum / pair.length)

Output [ 5, 3.5, 2, 2.5, 4 ]

A lot going there. Lets take it step by step

 var multiArray = [
...   [4, 1, 3],
...   [6, 4, 2, 3, 4],
...   [8, 6, 1, 2],
...   [2, 3]
... ];

Order the arrays so that the array with the most element becomes first

multiArray.sort( (x,y) => y.length - x.length)

[ [ 6, 4, 2, 3, 4 ], [ 8, 6, 1, 2 ], [ 4, 1, 3 ], [ 2, 3 ] ]

Take the first element and loop over its keys. This is the largest element as we have sorted it before.

Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0])

[ '0', '1', '2', '3', '4' ]

Now check if all the arrays have that key, else put an undefined over there

Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0]).
map( x => Object.keys(multiArray).
map(y => x < multiArray[y].length?multiArray[y][x]:undefined)).

[ [ 6, 8, 4, 2 ],
  [ 4, 6, 1, 3 ],
  [ 2, 1, 3, undefined ],
  [ 3, 2, undefined, undefined ],
  [ 4, undefined, undefined, undefined ] ]

Create an object with sum and length. This part is optional, but I wanted this to be clear

Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0]).
map( x => Object.keys(multiArray).
map(y => x < multiArray[y].length?multiArray[y][x]:undefined)).
map( a => ({sum: (a.reduce((l,r) => (l?l:0) + (r?r:0))), length: (a.filter(x => x).length)}) )

[ { sum: 20, length: 4 },
  { sum: 14, length: 4 },
  { sum: 6, length: 3 },
  { sum: 5, length: 2 },
  { sum: 4, length: 1 } ]

Finally get the avg

Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0]).
map( x => Object.keys(multiArray).
map(y => x < multiArray[y].length?multiArray[y][x]:undefined)).
map( a => ({sum: (a.reduce((l,r) => (l?l:0) + (r?r:0))), length: (a.filter(x => x).length)}) ).
map( pair => pair.sum / pair.length)

[ 5, 3.5, 2, 2.5, 4 ]

Upvotes: 0

Saeed
Saeed

Reputation: 5488

One solution is this:

1- Convert multiArray array to its vertical type (New array with their indexes as you said in question)

2- Calculate sum and then avg of each array.

var multiArray = [
    [4, 1, 3],
    [6, 4, 2, 3, 4],
    [8, 6, 1, 2],
    [2, 3]
  ],
  target = [];

multiArray.map((itm) => {
  let x = Object.keys(itm);
  x.forEach((ii) => {
    if (target.length <= ii) {
      target.push([]);
    }
    target[ii].push(itm[ii])
  });

});

target.forEach((arr)=> {
  let sum = arr.reduce(function(a, b) { return a + b; });
  let avg = sum / arr.length;
  console.log(avg)
})

Upvotes: 1

Ori Drori
Ori Drori

Reputation: 192477

Iterate the array with Array.reduce(). Iterate the sub array with Array.forEach(), and collect the sum, and the amount of items in the index. Use Array.map() to convert each sum/count object to average:

const multiArray = [
  [4, 1, 3],
  [6, 4, 2, 3, 4],
  [8, 6, 1, 2],
  [2, 3]
];

const result = multiArray
  .reduce((r, a) => {
    a.forEach((n, i) => {
      const { sum = 0, count = 0 } = r[i] || {};
      
      r[i] = { sum: sum + n, count: count + 1 };
    });
    
    return r;
  }, [])
  .map(({ sum, count }) => sum / count);
  
console.log(result);

Upvotes: 0

Related Questions