連想配列の数字の平均値の求め方について教えて下さい。こちらの続きになります。

http://q.hatena.ne.jp/1448507045


このような連想配列でキーごとに4番目のスコア(rec)の部分の平均値を求めてキーごとに表示させたいのですが方法がわかりません。
例)
UNIT1の平均値は@@点です。
UNIT2の平均値は@@点です。
連想配列に入れた後で、キーごとにスコアの数を数えて、その回数で割る方法を考えましたが合計点を求めるところがわかりません。また連想配列のデータのスコアの部分の合計点を求める場合、やはり、連想配列に入れたあとで、処理するのでしょうか?あるいは、入れながら足していくのか? 調べてみても1つのキーに対して数が1つの例しか見つからず、上のように1つのキーに得点が複数ある場合の処理の方法が理解できずにいます。アドバイスいたたければ幸いです。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2015/12/18 15:25:03

回答2件)

id:Lhankor_Mhy No.1

回答回数814ベストアンサー獲得回数232

var tableMap = {
UNIT1:["80", "40"],
UNIT2:["50", "60", "90"]
};

var averageMap = Object.keys(tableMap).reduce(function(map, key){
  var row = tableMap[key];
  map[key] = row.reduce(function(sum, value){return sum += parseFloat(value)},0) / row.length
  return map;
},{});

//{UNIT1:60, UNIT2:66.66666666666667}

無理に副作用を嫌ってかえって分かりにくいコードになる図。
 
分かりやすい回答はa-kuma3さんお願いします。

id:kajironpu

Lhankor_Mhyさん
さっそくありがとうございます。
お返事遅れて申し訳ありませんでした。
なかなかLhankor_Mhyさんのコードを理解するのは難しいですがとてもシンプルにまとまるのですね
じっくり勉強します。
ありがとうございました。

2015/12/14 10:25:00
id:a-kuma3 No.2

回答回数4974ベストアンサー獲得回数2154

ベタに書くとこんな感じになります。

var tableMap = {
    UNIT1:["80", "40"],
    UNIT2:["50", "60", "90"]
};

var averageMap = {};

for (var key in tableMap) {
    var data = tableMap[key];
    var sum = 0;
    for (var i = 0 ; i < data.length ; ++i) {
        sum += parseFloat(data[i]);
    }
    averageMap[key] = sum / data.length;
}

console.log(averageMap);    // Object { UNIT1: 60, UNIT2: 66.66666666666667 }

やってることは id:Lhankor_Mhy さんが書いたのと同じです。

Array#reduce って、使いどころが難しいメソッドだと思います。
メソッド名を素直に受け取れば、Array#filter メソッドで代替できるし、合計を求めるような N → 1 の「削減する」だったら「集約する」とかの方がメソッド名としてはピンとくるような感じがします。

ランカーさんの回答例にならったコードを回答には書きましたが、前の質問であったようなケースに組み込むのであれば、こんな感じかと。
https://jsfiddle.net/a_kuma3/yecrp2c1/1/

点数の表にくっつけるなら、こんな感じです。
https://jsfiddle.net/a_kuma3/k15k6k2w/2/

# 平均を求める所よりも、見た目を作るところの方が面倒です :-)

他6件のコメントを見る
id:a-kuma3

未実施を処理するループのところなんですが、i = 2 の三回目のループのときに、
averagedata[i] つまり、averagedata[2] が未定義なので、averagedata[i][0] を参照しようとしてエラーになってます(そこで、ループが止まる)。

ここでやりたいのは、averagedata に listdata[i] が、同じ順番のところではなく、どこかにあるかどうかを探さなくちゃいけません。
元になる得点データ dataArray4 を UNIT1 と UNIT2 ではなく、UNIT3 と UNIT4 に変えて試してみれば分かると思います。

こうしてみると、考えやすいと思います。

function searchAverageData(data, name) {
    // 配列の配列 data から、data[i][0] == name を探す
    ...

    return 平均得点;    // もし、見つからなかったら -1 を返す
}

result1 =[];
result =[];
for (var i = 0 ; i < listdata.length ; ++i) {
    var average = searchAverageData(averagedata, listdata[i]);
    if (average != -1){ // 見つからなかったら -1 が返る
        alert("○:リストにありました " + i + " : " + listdata[i])
        result1.push(averagedata[i][0]) //keyを入れる
        result1.push(averagedata[i][1]) //平均値を入れる
        result.push(result1)
    }

    else{
        alert("×:リストにありません " + i + " : " + listdata[i])
        result1.push(averagedata[i][0]) //keyを入れる
        result1.push("未実施") //未実施を入れる
        result.push(result1)
    }
    alert(result[i])
}

# ループの部分は、if の判定のところしか変えてません

「averagedata から listdata のそれぞれの名前を探す」というところが解決できれば、

  • 配列に入れるよりも、連想配列に入れた方が簡単だったんじゃないか
  • listdata にある全員のデータを別の配列に入れる処理にもミスがある

ということに、気付くと思います。

a-kuma3 さん、何度も恐縮です。

面倒になったら応えなくなるだけなので、あまり気にしなくて良いですよ。
そういうサイトなわけだし :-)

2015/12/15 16:22:49
id:kajironpu

a-kuma3さん、ありがとうございます。
https://jsfiddle.net/kajironpu/vqr6vq50/2/

なるほど、理解できました。
for (var i = 0 ; i < listdata.length ; ++i) {
if (averagedata[i][0] == listdata[i]){

ここで、リストの数だけ順番に回して探そうとしたのですが、averageデータのほうは実際は
少ない場合はデータがないのでエラーになっていたんですね。
firefoxでundefinedというのはそういうことだったのですね

function searchAverageData(data, name) {
// 配列の配列 data から、data[i][0] == name を探す
...

return 平均得点; // もし、見つからなかったら -1 を返す
}
上の関数で、データを見つけて取ってくるやり方(引数というやつでしょうか)
を是非トライしてみます。

ありがとうございます。

2015/12/16 10:10:40

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません