2013-02-13 8 views
5

2つの列の 'テーブル'が配列として表されています。JSは2次元配列の同じ要素の平均を計算します

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_array = [ [ 3,4,5,3,4,5,2 ],[ 12,14,16,11,12,10,20 ] ]; 

:最初の列1から20までの数字であり、それらが標識され、第2列は対応する値(秒)であります私の試み:

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

答えて

3

これはどのように(ネイティブJS、う)古いブラウザ上壊さない:

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、あなたは空想をしたい場合、私はそれを行うためにいくつかの他の方法を作成しました。それらは外部ライブラリに依存し、おそらくネイティブソリューションよりもはるかに低速です。しかし、彼らはは見てよかったです。

それはunderscore.jsで、次のようになります。

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

として:本当に偉大linq.js(私が使用したV2.2)と

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

またはこのような

、疑わしいことに、 "派手な"実装はネイティブの実装よりも遅いオーダーです: jsperf comparison

+0

ありがとうございます! - 男のJSは決してまっすぐ進むことはありません... – Chrugel

+0

いくつかの改善点: - 私はifテスト:index.hasOwnProperty(i)はユーザーがいないと思う。 - my_arrayに数字があるので、parseIntは役に立たないと思います。 - 発生するかどうかをテストするには、0ですか?代わりに。 ocurr == 0?0:sum/occur。 –

+0

明確にする:ありがとうございました!私は単純にこの答えを選んだ。それは正しい/期待された結果を「すぐに」提供する。 robertklepとAdrian Maireの(非常にエレガントな)ソリューションで、私は問題ではない私の 'label'-subarrayの文字列で終わるが、Tomalakは適切な解決法を提供した。 – 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

この関数は、結果の例のように結果の配列をソートしません。並べ替えが必要な場合は、私だけを言うと私はそれを追加します。

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; 
} 
関連する問題