JavaScript Tips | 配列ユーティリティ:サマリー生成

JavaScript JavaScript
スポンサーリンク
  1. テーマの整理:「サマリー生成」とは何か
  2. 基本コンセプト:「生データ配列」から「サマリーオブジェクト」を作る
    1. どんなデータからサマリーを作るのか
  3. ユーティリティ 1:基本的な数値サマリー(合計・平均・最大・最小)
    1. 実装:numericSummary
    2. 重要ポイントをかみ砕いて説明
    3. 例題 1:売上金額のサマリーを作る
  4. ユーティリティ 2:オブジェクト配列から「特定フィールドのサマリー」を作る
    1. シナリオ
    2. 実装:fieldNumericSummary
    3. 重要ポイントをかみ砕いて説明
    4. 例題 2:売上配列から amount のサマリーを作る
  5. ユーティリティ 3:カテゴリごとのサマリー(グルーピング+集計)
    1. シナリオ
    2. 実装:groupSummary
    3. 重要ポイントをかみ砕いて説明
    4. 例題 3:店舗ごとの売上サマリーを作る
  6. ユーティリティ 4:件数サマリー(条件ごとのカウント)
    1. シナリオ
    2. 実装:countBy
    3. 重要ポイントをかみ砕いて説明
    4. 例題 4:active フラグごとの件数サマリーを作る
  7. サマリー生成ユーティリティで意識してほしい重要ポイント
    1. 「生データを全部見なくても、サマリーだけで状況が分かる」状態を作る
    2. 「サマリーは“表示・レポート・監視”の入口になる」
  8. 手を動かして「サマリー生成」の感覚をつかむ
  9. まとめ:サマリー生成ユーティリティで「配列の海から、意味のある“要約”をすくい上げる」

テーマの整理:「サマリー生成」とは何か

ここでの「サマリー生成」は、配列に入っているたくさんのデータを「要約・集計」して、業務で使いやすい形にまとめるユーティリティのことです。 「生データの配列」から、次のような情報を取り出すイメージです。

  • 合計・平均・最大値・最小値
  • 件数(全体件数・条件に合う件数)
  • カテゴリごとの集計(店舗別、担当者別、ステータス別など)

ポイントは、「1 件ずつ眺める」のではなく、“配列全体を見て、要約情報を作る”ことです。

基本コンセプト:「生データ配列」から「サマリーオブジェクト」を作る

どんなデータからサマリーを作るのか

よくある形は、こんな売上データの配列です。

const sales = [
  { id: 1, store: "A", amount: 100, taxIncluded: true },
  { id: 2, store: "A", amount: 200, taxIncluded: false },
  { id: 3, store: "B", amount: 150, taxIncluded: true },
];
JavaScript

ここから、例えば次のようなサマリーを作りたくなります。

  • 全体の売上合計
  • 全体の平均金額
  • 店舗ごとの売上合計
  • 税込み・税抜きの件数

こういう「要約情報」を、配列から自動で生成するユーティリティがあると、 画面表示・レポート・ログ出力などでとても便利です。

ユーティリティ 1:基本的な数値サマリー(合計・平均・最大・最小)

実装:numericSummary

まずは、数値配列に対して「基本的なサマリー」を作るユーティリティです。

function numericSummary(values) {
  if (!Array.isArray(values) || values.length === 0) {
    return {
      count: 0,
      sum: 0,
      avg: 0,
      min: null,
      max: null,
    };
  }

  let sum = 0;
  let min = Number.POSITIVE_INFINITY;
  let max = Number.NEGATIVE_INFINITY;
  let count = 0;

  values.forEach((v) => {
    if (typeof v !== "number" || Number.isNaN(v)) {
      return;
    }
    sum += v;
    count += 1;
    if (v < min) min = v;
    if (v > max) max = v;
  });

  const avg = count === 0 ? 0 : sum / count;

  if (count === 0) {
    return {
      count: 0,
      sum: 0,
      avg: 0,
      min: null,
      max: null,
    };
  }

  return {
    count,
    sum,
    avg,
    min,
    max,
  };
}
JavaScript

重要ポイントをかみ砕いて説明

values が配列でない・空配列のときは、「全部 0・min/max は null」というサマリーを返します。 sum・min・max・count を自分で管理しながら、forEach で数値だけを集計しています。 数値でないものや NaN は無視しています(業務データには変な値が混ざることがあるので)。 平均 avg は「count が 0 のときは 0」「それ以外は sum / count」で計算しています。

これで、「数値配列の基本的なサマリー」が一発で手に入ります。

例題 1:売上金額のサマリーを作る

const amounts = [100, 200, 150];

const summary = numericSummary(amounts);

console.log(summary);
JavaScript

出力イメージはこうなります。

{
  count: 3,
  sum: 450,
  avg: 150,
  min: 100,
  max: 200
}
JavaScript

ここでのポイントは、「配列を見なくても、サマリーだけで全体のイメージがつかめる」ことです。 画面の上部に「合計」「平均」「最大」「最小」を出すときなどに、そのまま使えます。

ユーティリティ 2:オブジェクト配列から「特定フィールドのサマリー」を作る

シナリオ

売上配列から「amount のサマリー」を作りたい。 ユーザー配列から「age のサマリー」を作りたい。

実装:fieldNumericSummary

function fieldNumericSummary(records, field) {
  if (!Array.isArray(records) || records.length === 0) {
    return numericSummary([]);
  }

  const values = records
    .map((r) => r[field])
    .filter((v) => typeof v === "number" && !Number.isNaN(v));

  return numericSummary(values);
}
JavaScript

重要ポイントをかみ砕いて説明

records が配列でない・空配列なら、numericSummary([]) を返します。 指定フィールド field の値だけを取り出し、数値でないものや NaN をフィルタしています。 最後は numericSummary に渡して、基本サマリーを作っています。

これで、「オブジェクト配列の特定フィールドに対するサマリー」が簡単に作れます。

例題 2:売上配列から amount のサマリーを作る

const sales = [
  { id: 1, store: "A", amount: 100 },
  { id: 2, store: "A", amount: 200 },
  { id: 3, store: "B", amount: 150 },
];

const amountSummary = fieldNumericSummary(sales, "amount");

console.log(amountSummary);
JavaScript

出力イメージはこうなります。

{
  count: 3,
  sum: 450,
  avg: 150,
  min: 100,
  max: 200
}
JavaScript

この形は、ダッシュボードやレポートの「総売上」「平均単価」などにそのまま使えます。

ユーティリティ 3:カテゴリごとのサマリー(グルーピング+集計)

シナリオ

店舗ごとの売上サマリーを作りたい。 ステータスごとの件数・合計を出したい。

実装:groupSummary

まず、「グループキーごとに数値フィールドを集計する」ユーティリティを作ります。

function groupSummary(records, groupField, valueField) {
  if (!Array.isArray(records) || records.length === 0) {
    return {};
  }

  const groups = new Map();

  records.forEach((r) => {
    const key = r[groupField];
    const value = r[valueField];

    if (typeof value !== "number" || Number.isNaN(value)) {
      return;
    }

    if (!groups.has(key)) {
      groups.set(key, []);
    }

    groups.get(key).push(value);
  });

  const result = {};

  groups.forEach((values, key) => {
    result[key] = numericSummary(values);
  });

  return result;
}
JavaScript

重要ポイントをかみ砕いて説明

groupField(例: “store”)でグループキーを取り出し、valueField(例: “amount”)で数値を取り出します。 Map を使って「グループキー → 数値配列」の対応を作っています。 最後に、各グループの数値配列に対して numericSummary を適用し、 結果を普通のオブジェクト { storeA: {...}, storeB: {...} } にまとめています。

これで、「カテゴリごとのサマリー」が一発で作れます。

例題 3:店舗ごとの売上サマリーを作る

const sales = [
  { id: 1, store: "A", amount: 100 },
  { id: 2, store: "A", amount: 200 },
  { id: 3, store: "B", amount: 150 },
];

const storeSummary = groupSummary(sales, "store", "amount");

console.log(JSON.stringify(storeSummary, null, 2));
JavaScript

出力イメージはこうなります。

{
  "A": {
    "count": 2,
    "sum": 300,
    "avg": 150,
    "min": 100,
    "max": 200
  },
  "B": {
    "count": 1,
    "sum": 150,
    "avg": 150,
    "min": 150,
    "max": 150
  }
}
JavaScript

ここでのポイントは、

  • 店舗 A のサマリー
  • 店舗 B のサマリー

がそれぞれまとまっていることです。

この形は、画面で「店舗別の集計表」を出したり、 レポートで「店舗別の売上サマリー」を載せたりするときに、そのまま使えます。

ユーティリティ 4:件数サマリー(条件ごとのカウント)

シナリオ

「active なユーザーの件数」「inactive なユーザーの件数」を知りたい。 「税込み」「税抜き」の件数を知りたい。

実装:countBy

function countBy(records, field) {
  if (!Array.isArray(records) || records.length === 0) {
    return {};
  }

  const result = {};

  records.forEach((r) => {
    const key = r[field];
    const k = String(key);
    if (!result[k]) {
      result[k] = 0;
    }
    result[k] += 1;
  });

  return result;
}
JavaScript

重要ポイントをかみ砕いて説明

field の値をキーとして、件数をカウントしています。 キーは文字列にしておくと、true/false や数値も扱いやすくなります。 戻り値は { "true": 10, "false": 3 } のような形になります。

例題 4:active フラグごとの件数サマリーを作る

const users = [
  { id: 1, active: true },
  { id: 2, active: false },
  { id: 3, active: true },
];

const activeSummary = countBy(users, "active");

console.log(activeSummary);
JavaScript

出力イメージはこうなります。

{
  "true": 2,
  "false": 1
}
JavaScript

この形は、「ステータスごとの件数」を出すときにとても便利です。

サマリー生成ユーティリティで意識してほしい重要ポイント

「生データを全部見なくても、サマリーだけで状況が分かる」状態を作る

サマリー生成の目的は、「大量の配列を全部眺めなくても、要約だけで状況が分かるようにする」ことです。

  • 合計・平均・最大・最小で「全体の傾向」が分かる。
  • カテゴリごとのサマリーで「どこが強いか・弱いか」が分かる。
  • 件数サマリーで「どのステータスが多いか」が分かる。

初心者のうちは、

「この配列から、どんなサマリーがあると嬉しいか?」

と考えてみると、 どんなユーティリティを作るべきかが見えてきます。

「サマリーは“表示・レポート・監視”の入口になる」

サマリー生成ユーティリティは、 画面表示・レポート・監視・ログなどの「入口」によく使われます。

  • ダッシュボードの上部にサマリーを表示する。
  • CSV の先頭行にサマリー行を追加する。
  • ログに「処理対象のサマリー」を出しておく。

こうしておくと、後から見返したときに「何が起きていたか」がすぐ分かります。

手を動かして「サマリー生成」の感覚をつかむ

次のコードを実行して、

  • 数値サマリー
  • フィールドサマリー
  • グループサマリー
  • 件数サマリー

を一気に体感してみてください。

function numericSummary(values) {
  if (!Array.isArray(values) || values.length === 0) {
    return { count: 0, sum: 0, avg: 0, min: null, max: null };
  }

  let sum = 0;
  let min = Number.POSITIVE_INFINITY;
  let max = Number.NEGATIVE_INFINITY;
  let count = 0;

  values.forEach((v) => {
    if (typeof v !== "number" || Number.isNaN(v)) return;
    sum += v;
    count += 1;
    if (v < min) min = v;
    if (v > max) max = v;
  });

  const avg = count === 0 ? 0 : sum / count;

  if (count === 0) {
    return { count: 0, sum: 0, avg: 0, min: null, max: null };
  }

  return { count, sum, avg, min, max };
}

function fieldNumericSummary(records, field) {
  if (!Array.isArray(records) || records.length === 0) {
    return numericSummary([]);
  }
  const values = records
    .map((r) => r[field])
    .filter((v) => typeof v === "number" && !Number.isNaN(v));
  return numericSummary(values);
}

function groupSummary(records, groupField, valueField) {
  if (!Array.isArray(records) || records.length === 0) {
    return {};
  }

  const groups = new Map();

  records.forEach((r) => {
    const key = r[groupField];
    const value = r[valueField];
    if (typeof value !== "number" || Number.isNaN(value)) return;
    if (!groups.has(key)) {
      groups.set(key, []);
    }
    groups.get(key).push(value);
  });

  const result = {};
  groups.forEach((values, key) => {
    result[key] = numericSummary(values);
  });
  return result;
}

function countBy(records, field) {
  if (!Array.isArray(records) || records.length === 0) {
    return {};
  }
  const result = {};
  records.forEach((r) => {
    const key = String(r[field]);
    if (!result[key]) {
      result[key] = 0;
    }
    result[key] += 1;
  });
  return result;
}

function demo() {
  const sales = [
    { id: 1, store: "A", amount: 100, taxIncluded: true },
    { id: 2, store: "A", amount: 200, taxIncluded: false },
    { id: 3, store: "B", amount: 150, taxIncluded: true },
  ];

  console.log("=== numericSummary (amounts) ===");
  console.log(numericSummary(sales.map((s) => s.amount)));

  console.log("=== fieldNumericSummary (amount) ===");
  console.log(fieldNumericSummary(sales, "amount"));

  console.log("=== groupSummary (store, amount) ===");
  console.log(JSON.stringify(groupSummary(sales, "store", "amount"), null, 2));

  console.log("=== countBy (taxIncluded) ===");
  console.log(countBy(sales, "taxIncluded"));
}

demo();
JavaScript

まとめ:サマリー生成ユーティリティで「配列の海から、意味のある“要約”をすくい上げる」

サマリー生成は、 「大量の配列データから、業務で意味のある“要約情報”をすくい上げるためのユーティリティ」です。

プロジェクトに例えば次のような形で置いておくイメージです。

export function numericSummary(values) { ... }
export function fieldNumericSummary(records, field) { ... }
export function groupSummary(records, groupField, valueField) { ... }
export function countBy(records, field) { ... }
JavaScript

そして、

ダッシュボード表示前、 レポート生成前、 ログ出力前

など、「状況をざっくり把握したい場面」で必ずこのサマリー生成を通す。

こう決めておくと、 配列の海から「意味のある数字」だけを取り出せるようになり、 業務の判断や振り返りがぐっとやりやすくなります。

生データは“素材”、サマリーは“料理された結果”。 その料理を自動で作ってくれるのが、サマリー生成ユーティリティです。

タイトルとURLをコピーしました