Reputation: 751
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
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
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
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