何をしたいユーティリティか:「配列の最大値取得」
ここでの「最大値取得」は、配列の中で一番大きい値を取り出す処理です。
一番シンプルなのは「数値配列の最大値」ですが、業務では「オブジェクト配列の中で、特定の項目が最大のもの」を取りたいことも多いです。
例としては、次のような場面があります。
売上リストから「売上金額が最大の値」や「売上金額が最大のレコード」を取りたい。
スコア一覧から「最高スコア」を取りたい。
ログの中から「処理時間が最大のもの」を見つけたい。
これを毎回手書きするのではなく、「最大値取得ユーティリティ」としてまとめておくと、コードが読みやすくなります。
一番基本:数値配列の最大値を取得する
Math.max とスプレッド構文を使う方法
JavaScript には Math.max という「引数の中で最大の数値を返す」関数があります。
配列をそのまま渡すことはできませんが、スプレッド構文を使えば簡単に書けます。
function maxNumber(array) {
if (!Array.isArray(array) || array.length === 0) {
return undefined;
}
return Math.max(...array);
}
JavaScriptこの関数は、「数値だけが入っている配列」を前提にしています。
空配列や配列でないものが来たときは undefined を返すようにしておくと、呼び出し側で「最大値が存在しない」という状態を判定しやすくなります。
実際の動き
maxNumber([10, 5, 30, 7]);
// 30
maxNumber([-5, -10, -3]);
// -3
maxNumber([]);
// undefined
JavaScriptループで最大値を求める(考え方の基本)
自分で最大値を更新していく書き方
Math.max(...array) は便利ですが、「中で何が起きているか」を理解するために、ループで書いてみます。
function maxNumberLoop(array) {
if (!Array.isArray(array) || array.length === 0) {
return undefined;
}
let max = array[0];
for (let i = 1; i < array.length; i++) {
const value = array[i];
if (value > max) {
max = value;
}
}
return max;
}
JavaScriptここでやっていることはとてもシンプルです。
最初の要素を「暫定の最大値」として max に入れる。
2 番目以降の要素を順に見て、「今の max より大きければ max を更新する」。
最後まで見終わったときの max が「配列全体の最大値」になる。
この「暫定値を持っておいて、条件を満たしたら更新する」というパターンは、最大値だけでなく、最小値や合計値などでもよく使う基本形です。
オブジェクト配列から「特定の項目の最大値」を取る
「売上金額が最大の値」だけ欲しい場合
業務では、次のような配列がよく出てきます。
const sales = [
{ id: 1, amount: 1000 },
{ id: 2, amount: 5000 },
{ id: 3, amount: 3000 },
];
JavaScriptここから「amount の最大値だけ欲しい」場合は、まず amount だけを取り出してから maxNumber に渡す、という方法もあります。
function maxByKeyNumber(array, key) {
if (!Array.isArray(array) || array.length === 0) {
return undefined;
}
let max = undefined;
for (const item of array) {
if (!item || typeof item !== "object") continue;
const value = item[key];
if (typeof value !== "number") continue;
if (max === undefined || value > max) {
max = value;
}
}
return max;
}
JavaScriptこの関数は、「指定したキーの値が数値であるものだけ」を対象にして、その中の最大値を返します。
実際の動き
const sales = [
{ id: 1, amount: 1000 },
{ id: 2, amount: 5000 },
{ id: 3, amount: 3000 },
];
maxByKeyNumber(sales, "amount");
// 5000
JavaScript「最大値を持つ要素そのもの」を取りたい場合
一番売上が大きいレコードを丸ごと欲しい
多くの場合、「最大値そのもの」だけでなく、「最大値を持つレコード全体」が欲しくなります。
例えば、「売上金額が最大のレコード」を取りたいときです。
function maxItemByKey(array, key) {
if (!Array.isArray(array) || array.length === 0) {
return undefined;
}
let maxItem = undefined;
let maxValue = undefined;
for (const item of array) {
if (!item || typeof item !== "object") continue;
const value = item[key];
if (typeof value !== "number") continue;
if (maxValue === undefined || value > maxValue) {
maxValue = value;
maxItem = item;
}
}
return maxItem;
}
JavaScriptここでは、「最大値」と「最大値を持つ要素」の両方を持ちながらループしています。
maxValue は「今まで見た中での最大の数値」。maxItem は「その最大値を持っていたレコード」。
新しい要素を見たときに、「その要素の値が maxValue より大きければ、両方を更新する」という流れです。
実際の動き
const sales = [
{ id: 1, amount: 1000 },
{ id: 2, amount: 5000 },
{ id: 3, amount: 3000 },
];
maxItemByKey(sales, "amount");
// { id: 2, amount: 5000 }
JavaScriptこれで、「一番売上が大きいレコード」をそのまま扱えるようになります。
任意の「評価関数」で最大値を決める
key ではなく「関数」で柔軟に書く
「どの値を基準に最大を決めるか」を、キー名ではなく「関数」で渡せるようにすると、表現力が一気に上がります。
function maxBy(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;
}
JavaScriptscoreFn は、「要素を受け取って、その要素の“評価値(スコア)”を返す関数」です。
このスコアが最大の要素を返す、というユーティリティになっています。
実際の使い方
売上金額で最大を取りたいなら、こう書けます。
const maxSale = maxBy(sales, (item) => item.amount);
// { id: 2, amount: 5000 }
JavaScript「売上金額 ÷ コスト」のような複雑な指標で最大を取りたい場合も、関数の中で自由に計算できます。
const products = [
{ id: 1, price: 1000, cost: 800 },
{ id: 2, price: 2000, cost: 1200 },
{ id: 3, price: 1500, cost: 900 },
];
const best = maxBy(products, (p) => (p.price - p.cost) / p.cost);
// 利益率が最大の商品が返る
JavaScript実務で意識してほしい設計のポイント
「空のときどうするか」を必ず決める
最大値取得で一番ハマりやすいのは、「空配列から最大値を取ろうとしておかしくなる」パターンです。
Math.max(...[]) は -Infinity を返します。
これをそのまま使うと、「最大値が存在しないのに、なぜか -Infinity という値が入っている」という不自然な状態になります。
ユーティリティ側で、
空配列なら undefined を返す。
オブジェクト配列で「数値が一つもなかった」場合も undefined を返す。
と決めておくと、呼び出し側は「undefined なら最大値なし」と判断できて、バグを減らせます。
「最大値そのもの」と「最大値を持つ要素」を分けて考える
業務では、
最大値だけ欲しい場面。
最大値を持つレコード全体が欲しい場面。
の両方があります。
関数を分けておくと意図が明確になります。
maxNumber → 数値配列の最大値。maxByKeyNumber → オブジェクト配列の特定キーの最大値。maxItemByKey / maxBy → 最大値を持つ要素そのもの。
こうしておくと、「この関数は何を返すのか」が名前だけで分かるようになります。
「比較のルール」をユーティリティに閉じ込める
最大値取得は、「何を基準に大きいとみなすか」という比較ルールとセットです。
単純な数値なら > で十分ですが、
日付文字列や複合的な指標を扱う場合は、比較ロジックが少し複雑になります。
そのときに、画面やサービス層のあちこちに比較ロジックを書き散らすのではなく、
maxBy のようなユーティリティに「比較の基準(scoreFn)」を集約する。
という設計にしておくと、あとから仕様を変えたいときにも 1 箇所を直すだけで済みます。
少し手を動かして感覚をつかむ
コンソールで、次のようなコードを実際に打ってみてください。
maxNumber([10, 5, 30, 7]);
maxNumberLoop([10, 5, 30, 7]);
const sales = [
{ id: 1, amount: 1000 },
{ id: 2, amount: 5000 },
{ id: 3, amount: 3000 },
];
maxByKeyNumber(sales, "amount");
maxItemByKey(sales, "amount");
const products = [
{ id: 1, price: 1000, cost: 800 },
{ id: 2, price: 2000, cost: 1200 },
{ id: 3, price: 1500, cost: 900 },
];
maxBy(products, (p) => (p.price - p.cost) / p.cost);
JavaScript「どの値が最大として選ばれているか」「どのレコードが“最大のもの”として返ってきているか」を、自分の目で確認してみてください。
そのうえで、自分のプロジェクトに
export function maxNumber(...) { ... }
export function maxByKeyNumber(...) { ... }
export function maxItemByKey(...) { ... }
export function maxBy(...) { ... }
JavaScriptのような関数を置き、
「配列から最大値を取りたくなったら、必ずこの“最大値取得ユーティリティ”を通す」
というルールを作ってみてください。
それだけで、あなたの「最大値を探すコード」は、場当たり的な書き方から、意図と一貫性を備えた業務レベルの実装に変わっていきます。
