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

JavaScriptで複数の条件に基づいてJSONデータをグループ化し平均値を計算する方法


フロントエンド開発では、APIから取得したJSONデータを特定の条件で集約し、統計値を算出する処理が必要になることがよくあります。本記事では、複数のフィルター条件(「SupplierName」と「Category」)に基づいてオブジェクトの配列をグループ化し、ポイントの合計値と平均値を計算するJavaScriptの実装方法を、サンプルコード付きでわかりやすく解説します。

元データのサンプル

まず、以下のようなサプライヤーの評価データを含む配列を想定します。あえて、Pointsがundefinedになっている不正なレコードも含めています。

const arr = [
  { "SupplierName": "John", "Category": "A", "Points": 3 },
  { "SupplierName": "John", "Category": "A", "Points": 11 },
  { "SupplierName": "John", "Category": "A", "Points": undefined },
  { "SupplierName": "John", "Category": "B", "Points": 2 },
  { "SupplierName": "John", "Category": "B", "Points": 6 },
  { "SupplierName": "Praveen", "Category": "A", "Points": 3 },
  { "SupplierName": "Praveen", "Category": "A", "Points": 7 }
];

実現したい処理

この配列を受け取る関数には、次の役割を持たせます。

  • 同じ「SupplierName」と「Category」の組み合わせを持つオブジェクトを、1つのユニークなオブジェクトにまとめる
  • 各グループのポイント(Points)を合計する
  • 各オブジェクトに新たな「Average」フィールドを追加し、そのグループの平均ポイントを格納する
  • Pointsがundefinedなどの無効な値であるレコードは、集計対象から除外する

期待される出力

最終的な出力は次のようになります。

const output = [
  { "SupplierName": "John", "Category": "A", "Points": 14, "Average": 7 },
  { "SupplierName": "John", "Category": "B", "Points": 8, "Average": 4 },
  { "SupplierName": "Praveen", "Category": "A", "Points": 10, "Average": 5 }
];

実装コード

以下が実際のコードです。Array.prototype.reduce()を使ってグループ化を行い、その後で平均値を計算しています。

const groupAndAverage = (arr = []) => {
  const groups = arr.reduce((acc, obj) => {
    // SupplierNameとCategoryを組み合わせてユニークなキーを生成
    const key = `${obj.SupplierName}_${obj.Category}`;

    if (!acc[key]) {
      // グループが存在しない場合は新規作成
      // Averageはこの段階ではカウンターとして使用する
      acc[key] = {
        SupplierName: obj.SupplierName,
        Category: obj.Category,
        Points: 0,
        Average: 0
      };
    }

    // 有効な数値のみ集計(undefinedやnullは除外される)
    if (obj.Points) {
      acc[key].Points += obj.Points;
      acc[key].Average++;
    }

    return acc;
  }, {});

  // 合計ポイントを件数で割り、四捨五入して平均を求める
  return Object.values(groups).map(group => ({
    ...group,
    Average: Math.round(group.Points / group.Average)
  }));
};

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

実行結果

コンソールには以下が出力されます。

[
  {
    "SupplierName": "John",
    "Category": "A",
    "Points": 14,
    "Average": 7
  },
  {
    "SupplierName": "John",
    "Category": "B",
    "Points": 8,
    "Average": 4
  },
  {
    "SupplierName": "Praveen",
    "Category": "A",
    "Points": 10,
    "Average": 5
  }
]

コードの解説

  1. キーの生成: reduce()のコールバック内で、SupplierNameとCategoryをアンダースコアで連結した文字列(例:John_A)をグループ識別用のキーとしています。これにより、2つの条件を組み合わせた複合フィルターが実現できます。
  2. グループの初期化: 同じキーがまだ存在しない場合は、Pointsを0、Averageを0で初期化した新しいオブジェクトを作成します。Averageは最初の段階では「有効なレコード数」のカウンターとして機能します。
  3. 無効値の除外: if (obj.Points)という条件により、undefinedやnullといった無効な値を持つレコードは、合計にも件数にも含まれません。そのため、平均値の精度が保たれます。
  4. 平均の算出: 最終段階でObject.values()ですべてのグループを取り出し、合計ポイントをカウントで割った値をMath.round()で四捨五入しています。

応用のヒント

小数点以下の値も保持したい場合は、Math.round()の代わりに.toFixed(2)などを利用するとよいでしょう。また、グループ化の条件がさらに増える場合でも、キー生成の部分に条件を追加するだけで柔軟に拡張できます。大量のデータを扱うケースでは、通常のオブジェクトの代わりにMapを使うと、キー名の衝突を気にせず安全に管理できます。

  1. JavaScriptでtextareaに入力されたJSONデータを整形(プリティプリント)する方法

    textareaに入力されたJSONデータを整形(プリティプリント)して表示するには、JSON.parse()とJSON.stringify()を組み合わせて使用します。まずJSON.parse()で文字列をJavaScriptオブジェクトに変換し、その後JSON.stringify()の第3引数にインデント幅(例:4)を指定することで、インデントが整った読みやすいJSON文字列を取得できます。サンプルコード<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF

  2. Excelで複数の条件に基づいてテーブルからデータを抽出する方法

    必要なタイミングでデータを取り出せることは、スプレッドシートを活用するうえで最も重要な要素です。Excelも例外ではありません。私たちはデータを表形式でExcelに保存し、必要に応じてそれらを抽出します。本記事では、複数の条件(criteria)に基づいてテーブルからデータを抽出する方法を詳しく解説します。 まずはじめに、例のベースとなるデータセットを確認しておきましょう。 ここには、ジャンル・主演俳優・公開年とともに映画のリストがまとめられたテーブルがあります。このデータセットを使用して、複数の条件に基づいたデータ抽出を行います。 なお、説明をシンプルにするために基本的なテーブルを使用して