JS calculates the average of the same elements in a 2d array

I have a “table” of two columns represented as an array. The first column is numbers from 1 to 20, and they are labels, the second column is the corresponding values ​​(seconds):

my_array = [ [ 3,4,5,3,4,5,2 ],[ 12,14,16,11,12,10,20 ] ];

I need the average (average) for each label:

my_mean_array = [ [ 2,3,4,5 ],[ 20/1, (12+11)/2, (14+12)/2, (16+10)/2 ] ];
// edit: The mean should be a float - the notion above is just for clarification.
// Also the number 'labels' should remain as numbers/integers.

My attempt:

var a = my_array[0];
var b = my_array[1];
m = [];
n = [];
for( var i = 0; a.length; i++){
    m[ a[i] ] += b[i]; // accumulate the values in the corresponding place
    n[ a[i] ] += 1; // count the occurences
}
var o = [];
var p = [];
o = m / n;
p.push(n);
p.push(o);
+5
source share
3 answers

How about this (native JS will not break into older browsers):

function arrayMean(ary) {
  var index = {}, i, label, value, result = [[],[]];

  for (i = 0; i < ary[0].length; i++) {
    label = ary[0][i];
    value = ary[1][i];
    if (!(label in index)) {
      index[label] = {sum: 0, occur: 0};
    }
    index[label].sum += value;
    index[label].occur++;
  }
  for (i in index) {
    if (index.hasOwnProperty(i)) {
      result[0].push(parseInt(i, 10));
      result[1].push(index[i].occur > 0 ? index[i].sum / index[i].occur : 0);
    }
  }
  return result;
}

FWIW, if you want fantasy, I created several other ways to do this. They depend on external libraries and are probably an order of magnitude slower than their own solution. But they are nicer to watch.

It might look like this: underscore.js :

function arrayMeanUnderscore(ary) {
  return _.chain(ary[0])
    .zip(ary[1])
    .groupBy(function (item) { return item[0]; })
    .reduce(function(memo, items) {
      var values = _.pluck(items, 1),
          toSum = function (a, b) { return a + b; };

      memo[0].push(items[0][0]);
      memo[1].push(_(values).reduce(toSum) / values.length);
      return memo;
    }, [[], []])
    .value();
}

// --------------------------------------------

arrayMeanUnderscore([[3,4,5,3,4,5,2], [12,14,16,11,12,10,20]]);
// -> [[2,3,4,5], [20,11.5,13,13]]

, linq.js ( v2.2):

function arrayMeanLinq(ary) {
  return Enumerable.From(ary[0])
    .Zip(ary[1], "[$, $$]")
    .GroupBy("$[0]")
    .Aggregate([[],[]], function (result, item) {
      result[0].push(item.Key());
      result[1].push(item.Average("$[1]"));
      return result;
    });
}

// --------------------------------------------

arrayMeanLinq([[3,4,5,3,4,5,2], [12,14,16,11,12,10,20]]);
// -> [[3,4,5,2], [11.5,13,13,20]]

, "" , : jsperf.

+3
var temp = {}; 
my_array[0].map(function(label, i) {
  if (! temp[label])
  {
    temp[label] = [];
  }
  temp[label].push(my_array[1][i]);
});
var result = [ [], [] ];
for (var label in temp) {
  result[0].push(label);
  result[1].push(
    temp[label].reduce(function(p, v) { return p + v }) / temp[label].length
  );
}
0

This function does not sort the resulting array, as in the example with the results. If you need sorting, just tell me and I will add it.

function getMeanArray(my_array)
{
    m = {}; //id={count,value}
    for( var i = 0; i<my_array[0].length; i++){
        if (m[my_array[0][i]]===undefined)
        { 
            m[my_array[0][i]]={count:0, value:0};
        }
        m[ my_array[0][i] ].value += my_array[1][i]; // accumulate the values in the corresponding place
        m[ my_array[0][i] ].count++; // count the occurences
    }
    var my_mean_array=[[],[]];
    for (var id in m)
    {
        my_mean_array[0].push(id);
        my_mean_array[1].push(m[id].count!=0?m[id].value/m[id].count:0);
    }
    return my_mean_array;
}
0
source

All Articles