JavaScript Tips | 配列ユーティリティ:合計算出

JavaScript JavaScript
スポンサーリンク

何をしたいユーティリティか:「配列の合計算出」

ここでの「合計算出」は、配列の中の値を全部足して、ひとつの数値にまとめる処理です。
一番シンプルなのは「数値配列の合計」ですが、業務では「オブジェクト配列の中の特定の項目の合計」を出したいことがほとんどです。

例えば、こんな場面で使います。

売上リストから「売上金額の合計」を出したい。
請求明細から「数量 × 単価の合計」を出したい。
ログから「処理時間の合計」や「エラー件数の合計」を出したい。

これを毎回 for 文で書くのではなく、「合計算出ユーティリティ」としてまとめておくと、コードがかなり読みやすくなります。


一番基本:数値配列の合計を求める

シンプルなループでの合計

まずは、数値だけが入っている配列の合計です。

function sumNumbers(array) {
  if (!Array.isArray(array) || array.length === 0) {
    return 0;
  }

  let total = 0;

  for (const value of array) {
    if (typeof value !== "number") {
      continue;
    }
    total += value;
  }

  return total;
}
JavaScript

ここで大事なのは、「合計の初期値」と「足し方」です。

total を 0 で始めて、配列の要素を順番に見ながら total += value で足していきます。
数値でないものが混ざっていたらスキップするようにしておくと、変な値が紛れ込んでも壊れにくくなります。

実際の動き

sumNumbers([10, 20, 30]);
// 60

sumNumbers([1, 2, 3, 4, 5]);
// 15

sumNumbers([]);
// 0

sumNumbers([10, "20", 30]);
// 40  ("20" は数値でないのでスキップ)
JavaScript

「空配列なら 0 を返す」という仕様にしておくと、呼び出し側で扱いやすくなります。


reduce を使った書き方(中身の意味も理解する)

reduce 版の実装

同じことは Array.prototype.reduce を使っても書けます。

function sumNumbersReduce(array) {
  if (!Array.isArray(array) || array.length === 0) {
    return 0;
  }

  return array.reduce((total, value) => {
    if (typeof value !== "number") {
      return total;
    }
    return total + value;
  }, 0);
}
JavaScript

reduce の第 2 引数の 0 が「合計の初期値」です。
コールバックの total が「今までの合計」、value が「今見ている要素」です。

total + value を返すことで、「前までの合計に今の値を足したもの」が次のループに渡されていきます。
最後まで回ったときの total が、配列全体の合計になります。

「ループで書くとこうなるものを、1 行に圧縮したもの」として理解すると、reduce が怖くなくなります。


オブジェクト配列から「特定の項目の合計」を出す

金額や数量の合計を出したいケース

業務では、次のような配列がよく出てきます。

const items = [
  { id: 1, price: 1000, quantity: 2 },
  { id: 2, price: 500, quantity: 3 },
  { id: 3, price: 2000, quantity: 1 },
];
JavaScript

ここから、「price の合計」や「price × quantity の合計」を出したくなります。

まずは「特定のキーの数値を足す」ユーティリティです。

function sumByKeyNumber(array, key) {
  if (!Array.isArray(array) || array.length === 0) {
    return 0;
  }

  let total = 0;

  for (const item of array) {
    if (!item || typeof item !== "object") {
      continue;
    }

    const value = item[key];

    if (typeof value !== "number") {
      continue;
    }

    total += value;
  }

  return total;
}
JavaScript

この関数は、「指定したキーの値が数値であるものだけ」を対象にして、その合計を返します。

実際の動き

const items = [
  { id: 1, price: 1000, quantity: 2 },
  { id: 2, price: 500, quantity: 3 },
  { id: 3, price: 2000, quantity: 1 },
];

sumByKeyNumber(items, "price");
// 3500
JavaScript

「計算した値」の合計を出す(例:金額=単価×数量)

単純なキーでは足りない場合

多くの業務では、「そのままの値」ではなく、「計算した結果」の合計が欲しくなります。
例えば、「price × quantity の合計金額」です。

この場合は、「要素から合計対象の数値を取り出す関数」を渡せるようにすると便利です。

function sumBy(array, valueFn) {
  if (!Array.isArray(array) || array.length === 0) {
    return 0;
  }

  let total = 0;

  for (const item of array) {
    const value = valueFn(item);

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

    total += value;
  }

  return total;
}
JavaScript

valueFn は、「要素を受け取って、その要素から“足したい数値”を返す関数」です。

実際の使い方

単価の合計ならこう書けます。

sumBy(items, (item) => item.price);
// 3500
JavaScript

「金額=単価×数量」の合計ならこうです。

sumBy(items, (item) => item.price * item.quantity);
// 1000*2 + 500*3 + 2000*1 = 5500
JavaScript

このように、「合計対象の値をどう計算するか」を valueFn に閉じ込めておくと、
ユーティリティ側は「それをひたすら足すだけ」で済みます。


実務で意識してほしい設計のポイント

空配列のときは「0」を返すかどうか

合計のときは、空配列なら 0 を返す設計が自然です。
数学的にも「空の和は 0」と考えるのが一般的です。

undefined を返す設計もありえますが、業務コードでは「0 のほうが扱いやすい」ことが多いです。
例えば、「合計金額を表示する」「合計件数をログに出す」といった場面で、
undefined より 0 のほうがそのまま使いやすいからです。

なので、合計ユーティリティは、

数値配列の合計 → 空なら 0。
オブジェクト配列の合計 → 対象が一つもなければ 0。

という仕様にしておくと、呼び出し側がシンプルになります。

「数値でないものが混ざったとき」の扱い

現実のデータはきれいとは限らず、
"1000" のような文字列や null が紛れ込んでいることもあります。

ここでの方針は大きく 2 つです。

数値でないものは無視して足し続ける。
数値でないものがあったらエラーにする。

ユーティリティとしては「無視して足す」ほうが安全ですが、
「データがおかしいことに気づきたい」場面では、ログを出したり、バリデーションで弾いたりするのも有効です。

少なくとも、「Number(value) で無理やり数値にして足す」のは危険です。
Number("abc")NaN になり、そのまま足すと合計が NaN になってしまうからです。

今回の sumBy では、Number.isNaN(value) をチェックして、
おかしな値はスキップするようにしています。

「合計」と「平均」「最大・最小」はセットで考える

合計を出したら、次に欲しくなるのは「平均」や「最大・最小」です。
例えば、「平均単価」「最大金額」「最小金額」などです。

設計としては、

合計を出すユーティリティ(sumNumbers, sumBy
件数を数えるユーティリティ
最大・最小を出すユーティリティ

を組み合わせて、「平均」などの指標を作るときれいです。

例えば、平均を出す関数は「合計 ÷ 件数」で書けます。

function averageBy(array, valueFn) {
  if (!Array.isArray(array) || array.length === 0) {
    return undefined;
  }

  let total = 0;
  let count = 0;

  for (const item of array) {
    const value = valueFn(item);
    if (typeof value !== "number" || Number.isNaN(value)) {
      continue;
    }
    total += value;
    count += 1;
  }

  if (count === 0) {
    return undefined;
  }

  return total / count;
}
JavaScript

こうして、「合計算出ユーティリティ」を軸に、他の集計処理も組み立てていけます。


少し手を動かして感覚をつかむ

コンソールで、次のようなコードを実際に打ってみてください。

sumNumbers([10, 20, 30]);
sumNumbersReduce([10, 20, 30]);

const items = [
  { id: 1, price: 1000, quantity: 2 },
  { id: 2, price: 500, quantity: 3 },
  { id: 3, price: 2000, quantity: 1 },
];

sumByKeyNumber(items, "price");
sumBy(items, (item) => item.price * item.quantity);
JavaScript

「どんな値が合計されているか」「空配列のときにどうなるか」を、自分の目で確認してみてください。

そのうえで、自分のプロジェクトに

export function sumNumbers(...) { ... }
export function sumNumbersReduce(...) { ... }
export function sumByKeyNumber(...) { ... }
export function sumBy(...) { ... }
JavaScript

のような関数を置き、

「配列から合計を出したくなったら、必ずこの“合計算出ユーティリティ”を通す」

というルールを作ってみてください。
それだけで、あなたの集計コードは、場当たり的な for 文から、意図と一貫性を備えた業務レベルの実装に近づいていきます。

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