JavaScript Tips | 配列ユーティリティ:最小値取得

JavaScript JavaScript
スポンサーリンク

何をしたいユーティリティか:「配列の最小値取得」

ここでの「最小値取得」は、配列の中で一番小さい値を取り出す処理です。
「最大値取得」の逆ですが、業務では同じくらい頻繁に使います。

例えばこんな場面があります。

最も安い価格を知りたい。
最も短い処理時間を知りたい。
最も古い日付(最小のタイムスタンプ)を知りたい。

毎回 for 文を書くのではなく、「最小値取得ユーティリティ」としてまとめておくと、コードが読みやすくなります。


一番基本:数値配列の最小値を取得する

Math.min とスプレッド構文を使う

JavaScript には Math.min という「引数の中で最小の数値を返す」関数があります。
配列をそのまま渡せないので、スプレッド構文を使います。

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

  return Math.min(...array);
}
JavaScript

空配列や配列でないものが来たときは undefined を返すようにしておくと、
「最小値が存在しない」という状態を呼び出し側で判定しやすくなります。

実際の動き

minNumber([10, 5, 30, 7]);
// 5

minNumber([-5, -10, -3]);
// -10

minNumber([]);
// undefined
JavaScript

ループで最小値を求める(考え方の基本)

自分で「暫定の最小値」を更新していく

中で何が起きているかを理解するために、ループで書いてみます。

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

  let min = array[0];

  for (let i = 1; i < array.length; i++) {
    const value = array[i];
    if (value < min) {
      min = value;
    }
  }

  return min;
}
JavaScript

やっていることはこうです。

最初の要素を「暫定の最小値」として min に入れる。
2 番目以降の要素を順に見て、「今の min より小さければ min を更新する」。
最後まで見終わったときの min が「配列全体の最小値」になる。

この「暫定値を持っておいて、条件を満たしたら更新する」パターンは、最大値・最小値・合計値などで共通する基本形です。


オブジェクト配列から「特定の項目の最小値」を取る

「最小の値だけ欲しい」場合

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

const products = [
  { id: 1, price: 1000 },
  { id: 2, price: 500 },
  { id: 3, price: 1500 },
];
JavaScript

ここから「price の最小値だけ欲しい」場合のユーティリティです。

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

  let min = undefined;

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

    const value = item[key];

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

    if (min === undefined || value < min) {
      min = value;
    }
  }

  return min;
}
JavaScript

数値でないものはスキップし、「数値として比較できるものだけ」の最小値を返します。

実際の動き

const products = [
  { id: 1, price: 1000 },
  { id: 2, price: 500 },
  { id: 3, price: 1500 },
];

minByKeyNumber(products, "price");
// 500
JavaScript

「最小値を持つ要素そのもの」を取りたい場合

一番安い商品を丸ごと欲しい

多くの場合、「最小値そのもの」だけでなく、「最小値を持つレコード全体」が欲しくなります。

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

  let minItem = undefined;
  let minValue = undefined;

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

    const value = item[key];

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

    if (minValue === undefined || value < minValue) {
      minValue = value;
      minItem = item;
    }
  }

  return minItem;
}
JavaScript

minValue は「今まで見た中での最小の数値」、
minItem は「その最小値を持っていたレコード」です。

新しい要素を見たときに、「その値が minValue より小さければ、両方を更新する」という流れです。

実際の動き

const products = [
  { id: 1, price: 1000 },
  { id: 2, price: 500 },
  { id: 3, price: 1500 },
];

minItemByKey(products, "price");
// { id: 2, price: 500 }
JavaScript

任意の「評価関数」で最小値を決める

関数で「何を小さいとみなすか」を渡す

キー名ではなく、「要素から評価値を計算する関数」を渡せるようにすると、表現力が上がります。

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

  let bestItem = undefined;
  let bestScore = undefined;

  for (const item of array) {
    const score = scoreFn(item);

    if (score == null || Number.isNaN(score)) {
      continue;
    }

    if (bestScore === undefined || score < bestScore) {
      bestScore = score;
      bestItem = item;
    }
  }

  return bestItem;
}
JavaScript

scoreFn は、「要素を受け取って、その要素の“評価値(スコア)”を返す関数」です。
このスコアが最小の要素を返すユーティリティになります。

実際の使い方

最小価格の商品を取りたいならこう書けます。

const cheapest = minBy(products, (p) => p.price);
// { id: 2, price: 500 }
JavaScript

「納期(deliveryDays)が最も短いもの」なども同じです。

const plans = [
  { id: 1, deliveryDays: 7 },
  { id: 2, deliveryDays: 3 },
  { id: 3, deliveryDays: 5 },
];

const fastest = minBy(plans, (p) => p.deliveryDays);
// { id: 2, deliveryDays: 3 }
JavaScript

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

空配列や「比較対象がない」場合の扱いを決める

Math.min(...[])Infinity を返します。
これをそのまま使うと、「最小値が存在しないのに、なぜか Infinity が入っている」という不自然な状態になります。

ユーティリティ側で、

空配列なら undefined を返す。
オブジェクト配列で「数値が一つもなかった」場合も undefined を返す。

と決めておくと、呼び出し側は「undefined なら最小値なし」と判断できて、バグを減らせます。

「値だけ欲しい」と「要素ごと欲しい」を分ける

業務では、

最小値だけ欲しい場面。
最小値を持つレコード全体が欲しい場面。

の両方があります。

関数を分けておくと意図が明確になります。

minNumber → 数値配列の最小値。
minByKeyNumber → オブジェクト配列の特定キーの最小値。
minItemByKey / minBy → 最小値を持つ要素そのもの。

名前を見ただけで「何が返ってくるか」が分かるようにしておくと、後から読む人にも優しいです。

「比較のルール」をユーティリティに閉じ込める

最小値取得は、「何を基準に小さいとみなすか」という比較ルールとセットです。

単純な数値なら < で十分ですが、
日付文字列や複合的な指標(コスト、納期、リスクなど)を扱う場合は、比較ロジックが少し複雑になります。

そのときに、画面やサービス層のあちこちに比較ロジックを書き散らすのではなく、

minBy のようなユーティリティに「比較の基準(scoreFn)」を集約する。

という設計にしておくと、あとから仕様を変えたいときにも 1 箇所を直すだけで済みます。


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

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

minNumber([10, 5, 30, 7]);
minNumberLoop([10, 5, 30, 7]);

const products = [
  { id: 1, price: 1000 },
  { id: 2, price: 500 },
  { id: 3, price: 1500 },
];

minByKeyNumber(products, "price");
minItemByKey(products, "price");

const plans = [
  { id: 1, deliveryDays: 7 },
  { id: 2, deliveryDays: 3 },
  { id: 3, deliveryDays: 5 },
];

minBy(plans, (p) => p.deliveryDays);
JavaScript

「どの値が最小として選ばれているか」「どのレコードが“最小のもの”として返ってきているか」を、自分の目で確認してみてください。

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

export function minNumber(...) { ... }
export function minByKeyNumber(...) { ... }
export function minItemByKey(...) { ... }
export function minBy(...) { ... }
JavaScript

のような関数を置き、

「配列から最小値を取りたくなったら、必ずこの“最小値取得ユーティリティ”を通す」

というルールを作ってみてください。
それだけで、あなたの「最小値を探すコード」は、場当たり的な書き方から、意図と一貫性を備えた業務レベルの実装に変わっていきます。

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