2013-02-13 24 views
5

Mam "tabela" dwóch kolumn reprezentowanych jako tablica. Pierwsza kolumna są liczbami od 1 do 20 i są etykiety, druga kolumna są odpowiednie wartości (sekundy):JS obliczyć średnią tych samych elementów w tablicy 2d

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

trzeba średnią (średnia) dla poszczególnych etykiet:

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. 

Moja próba:

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

Odpowiedz

3

Jak o tym (native JS, będzie nie złamać na starszych przeglądarek):

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, jeśli chcesz fantazyjne Utworzyłem kilka innych sposobów, aby to zrobić. Zależą od bibliotek zewnętrznych i są prawdopodobnie o rząd wielkości wolniejsze niż rozwiązanie natywne. Ale są one przyjemniejsze do obejrzenia.

mogłoby to wyglądać tak, ze 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]] 

lub tak, z naprawdę wielką linq.js (używałem 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]] 

As podejrzewa się, że "fantazyjne" wdrożenia są o rząd wielkości wolniejsze niż natywna implementacja: jsperf comparison.

+0

Dziękujemy! - Man JS nigdy nie jest prosty ... – Chrugel

+0

kilka ulepszeń: - Myślę, że test if: index.hasOwnProperty (i) jest bez userless. - Myślę, że parseInt jest bezużyteczny, ponieważ my_array ma numery. - Aby sprawdzić, czy występuje 0, użyj zdania? zamiast. ocurr == 0? 0: suma/zdarzenie. –

+0

Aby wyjaśnić: Dziękuję wszystkim! Po prostu wybrałem tę odpowiedź, b/c daje mi prawidłowy/oczekiwany rezultat "po wyjęciu z pudełka". Dzięki (bardzo eleganckiemu) rozwiązaniu z robertklep i Adrian Maire kończę z ciągami w mojej "etykiecie" - subarray, co nie stanowi problemu, ale Tomalak dostarczył odpowiednie rozwiązanie. – 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

Ta funkcja nie sortuje wynikowej tablicy, jak w przykładowym wyniku. Jeśli potrzebujesz sortowania, po prostu powiedz mnie, a dodam.

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; 
} 
Powiązane problemy