JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptで各科目の最高スコアを持つ配列要素を取得する方法

課題:科目ごとの最高得点者を求める

まず、生徒の科目名・氏名・点数を格納したネストされた配列(配列の中に配列がある構造)を用意します。

const arr = [
  ['Math', 'John', 100],
  ['Math', 'Jake', 89],
  ['Math', 'Amy', 93],
  ['Science', 'Jake', 89],
  ['Science', 'John', 89],
  ['Science', 'Amy', 83],
  ['English', 'John', 82],
  ['English', 'Amy', 81],
  ['English', 'Jake', 72]
];

この配列を受け取り、「1科目につき1つのオブジェクト」を要素とする配列を返す関数を作成します。各オブジェクトには、その科目の最高得点者の名前と点数を含めます。なお、最高点が同点の場合は、該当する全員を出力に含める必要があります。

期待される出力は以下のとおりです。

[
  {
    'Subject': 'Math',
    'Top': [
      { 'name': 'John', 'score': 100 }
    ]
  },
  {
    'Subject': 'Science',
    'Top': [
      { 'name': 'Jake', 'score': 89 },
      { 'name': 'John', 'score': 89 }
    ]
  },
  {
    'Subject': 'English',
    'Top': [
      { 'name': 'John', 'score': 82 }
    ]
  }
]

実装コード

このような集計処理には Array.prototype.reduce() を使うのが効果的です。累積配列(acc)に対して、以下のルールで処理を進めます。

  • まだ存在しない科目であれば、新しいオブジェクトを追加する
  • 既存の科目であれば、現在の最高点より高ければ「Top」を差し替え、同点なら「Top」に追加する
const arr = [
  ['Math', 'John', 100],
  ['Math', 'Jake', 89],
  ['Math', 'Amy', 93],
  ['Science', 'Jake', 89],
  ['Science', 'John', 89],
  ['Science', 'Amy', 83],
  ['English', 'John', 82],
  ['English', 'Amy', 81],
  ['English', 'Jake', 72]
];

const groupScore = arr => {
  return arr.reduce((acc, val) => {
    const [sub, name, score] = val;
    const ind = acc.findIndex(el => el['Subject'] === val[0]);
    if (ind !== -1) {
      if (score > acc[ind]['Top'][0]['score']) {
        acc[ind]['Top'] = [{ 'name': name, 'score': score }];
      } else if (score === acc[ind]['Top'][0]['score']) {
        acc[ind]['Top'].push({ 'name': name, 'score': score });
      }
    } else {
      acc.push({
        'Subject': sub,
        'Top': [{ 'name': name, 'score': score }]
      });
    }
    return acc;
  }, []);
};

console.log(JSON.stringify(groupScore(arr), undefined, 4));

コードのポイント解説

1. 分割代入で値を取り出す

const [sub, name, score] = val; の部分では、各サブ配列から科目名・氏名・点数を一度に取り出しています。これによりコードが読みやすくなります。

2. 科目の存在チェック

findIndex() を使い、累積配列内に同じ科目のオブジェクトがすでに存在するかを確認します。見つからない場合は -1 が返るため、そのときは新規オブジェクトを push します。

3. 最高点の比較と更新

既存の科目が見つかった場合は、次の3パターンに分岐します。

  • 現在の点数が記録中の最高点より大きい → 「Top」を新しい1件だけで置き換える
  • 最高点と同じ → 同着として「Top」配列に追加する
  • それより低い → 何もしない

出力結果

コンソールには次のように表示されます。

[
  {
    'Subject': 'Math',
    'Top': [
      { 'name': 'John', 'score': 100 }
    ]
  },
  {
    'Subject': 'Science',
    'Top': [
      { 'name': 'Jake', 'score': 89 },
      { 'name': 'John', 'score': 89 }
    ]
  },
  {
    'Subject': 'English',
    'Top': [
      { 'name': 'John', 'score': 82 }
    ]
  }
]

このように reduce() を活用すれば、元のデータを1回走査するだけで、科目別の最高得点者リスト(同点者を含む)を効率的に生成できます。データ量が多い場合でもパフォーマンスよく動作する、実用的なパターンです。

  1. JavaScriptでnewキーワードを使って配列を作成する方法

    JavaScriptでは、newキーワードとArray()コンストラクタを使用することで、簡単に配列を作成できます。本記事では、実際に動作するサンプルコードとともに、その基本的な使い方を解説します。 サンプルコード 以下は、newキーワードを使用してJavaScriptの配列を作成するコード例です。 <!DOCTYPE html> <html lang=ja> <head> <meta charset=UTF-8 /> <meta name=viewport content=width=device-width, initial-sca

  2. 【JavaScript】filterとjoinを組み合わせて、条件に合う配列要素だけを結合する方法

    JavaScriptでは、filter()メソッドとjoin()メソッドを組み合わせることで、条件を満たす要素だけを抽出し、それらを任意の区切り文字で1つの文字列に結合できます。本記事では、配列の中から「2で割り切れる要素(偶数)」だけを取り出して結合する具体例を、動作するサンプルコードとともに解説します。 処理の流れ:filter() と join() の役割 filter():コールバック関数が true を返した要素だけを集めた新しい配列を作成します。元の配列は変更されません。 join():配列内のすべての要素を、引数で指定した区切り文字で連結し、1つの文字列として返します。引数