2013-02-13 13 views
5

Ich habe eine 'Tabelle' von zwei Spalten als ein Array dargestellt. In der ersten Spalte sind Zahlen von 1 bis 20 und sie sind Etiketten, die zweite Spalte gibt die entsprechenden Werte (Sekunden):JS berechnen Mittelwert der gleichen Elemente in 2d Array

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

I die mittlere benötigen (Mittelwert) für jedes Etikett:

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. 

Mein Versuch:

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); 

Antwort

3

Wie über diese (native JS, wird nicht auf älteren Browsern Pause):

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, wenn Sie Lust will es Ich habe ein paar andere Möglichkeiten geschaffen zu tun. Sie hängen von externen Bibliotheken ab und sind sehr wahrscheinlich eine Größenordnung langsamer als eine native Lösung. Aber sie sind netter zu betrachten.

Es könnte wie folgt aussehen, mit 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]] 

oder wie diese, mit der wirklich großen linq.js (I verwendet v2.2 habe):

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]] 

Wie vermutete, die "Phantasie" Implementierungen sind eine Größenordnung langsamer als eine native Implementierung: jsperf comparison.

+0

Vielen Dank! - Man JS ist nie geradlinig ... – Chrugel

+0

ein paar Verbesserungen: - Ich denke, dass der if test: index.hasOwnProperty (i) ist useless. - Ich denke, parseInt ist nutzlos, da my_array Nummern hat. - Um zu testen, ob der Wert 0 ist, benutze den Satz? stattdessen. ocurr == 0? 0: Summe/auftreten. –

+0

Nur um zu verdeutlichen: Danke euch allen! Ich habe einfach diese Antwort gewählt, b/c gibt mir das richtige/erwartete Ergebnis "out of the box". Mit der (sehr eleganten) Lösung von robertklep & Adrian Maire habe ich Streicher in meinem 'Label'-Subarray, was kein Problem ist, aber Tomalak lieferte eine passende Lösung. – Chrugel

0
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

Diese Funktion sortiert das resultierende Array nicht wie in Ihrem Ergebnisbeispiel. Wenn Sie sortieren müssen, sagen Sie mir einfach und ich werde es hinzufügen.

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; 
} 
Verwandte Themen