【JavaScript】配列から最小値・最大値を取得する方法|Math.max / Math.min・reduce・スプレッド構文の注意点・オブジェクト配列まで解説

テストの最高点・最低点、センサーデータの最大値・最小値、価格帯の取得など、配列から最小値と最大値を取得する操作はプログラミングの基本です。JavaScript では Math.max / Math.min とスプレッド構文の組み合わせが最もシンプルですが、大規模配列ではスタックオーバーフローの注意が必要です。

この記事でわかること
・Math.max / Math.min + スプレッド構文の基本
・reduce で大規模配列に安全に対応する方法
・for ループで最小値と最大値を同時取得する方法
・スプレッド構文のスタックオーバーフロー問題
・オブジェクト配列から特定プロパティの最大値・最小値を取得
・NaN / undefined / 空配列への対策
・最大値・最小値のインデックスを取得する方法
・N 番目に大きい値を取得する方法
スポンサーリンク

方法の比較

方法 コード 大規模配列 推奨場面
Math.max + … Math.max(...arr) × スタックオーバーフロー 数千件以下の配列
reduce arr.reduce((a,b) => Math.max(a,b)) ○ 安全 大規模配列・汎用
for ループ for + if ○ 最速 パフォーマンス重視

Math.max / Math.min + スプレッド構文(基本)

JavaScript
const scores = [85, 92, 78, 96, 88];

const max = Math.max(...scores);
const min = Math.min(...scores);

console.log(`最大値: ${max}`); // 96
console.log(`最小値: ${min}`); // 78

Math.max()Math.min() は個別の引数を取るメソッドのため、配列を直接渡せません。スプレッド構文 ... で配列を展開して引数として渡します。

スタックオーバーフローの注意

スプレッド構文は配列の全要素を関数の引数として展開するため、要素数が多すぎるとスタックオーバーフローが発生します。

NG: 大規模配列
// 要素数が数万件以上でエラーになる可能性
const huge = Array.from({ length: 100000 }, () => Math.random());
// Math.max(...huge); // RangeError: Maximum call stack size exceeded
スプレッド構文は数千件程度までは問題ありませんが、数万件以上の配列では reduce または for ループを使ってください。

reduce で安全に取得する

reduce は要素を 1 つずつ処理するためスタックオーバーフローの心配がなく、大規模配列にも安全に使えます。

JavaScript
const scores = [85, 92, 78, 96, 88];

const max = scores.reduce((a, b) => Math.max(a, b), -Infinity);
const min = scores.reduce((a, b) => Math.min(a, b), Infinity);

console.log(`最大値: ${max}`); // 96
console.log(`最小値: ${min}`); // 78

最大値と最小値を同時に取得する

JavaScript
const scores = [85, 92, 78, 96, 88];

const { max, min } = scores.reduce(
  (acc, val) => ({
    max: Math.max(acc.max, val),
    min: Math.min(acc.min, val)
  }),
  { max: -Infinity, min: Infinity }
);

console.log(`最大値: ${max}, 最小値: ${min}`); // 96, 78
reduce で同時に取得すれば、配列を1 回のループで最大値と最小値の両方を計算できます。

for ループで取得する(最速)

JavaScript
function getMinMax(arr) {
  let min = Infinity;
  let max = -Infinity;

  for (let i = 0; i < arr.length; i++) {
    if (arr[i] < min) min = arr[i];
    if (arr[i] > max) max = arr[i];
  }

  return { min, max };
}

const result = getMinMax([85, 92, 78, 96, 88]);
console.log(result); // { min: 78, max: 96 }
パフォーマンスを最優先するなら for ループが最速です。reduce より関数呼び出しのオーバーヘッドが少ないため、数十万件以上のデータでは差が出ます。

空配列・NaN・undefined への対策

ケース Math.max(…arr) 対策
空配列 [] -Infinity 事前に arr.length チェック
NaN を含む NaN filter(Number.isFinite) で除外
undefined を含む NaN filter(v => v != null) で除外
JavaScript
// 空配列
console.log(Math.max(...[])); // -Infinity

// NaN を含む配列
console.log(Math.max(1, NaN, 3)); // NaN

// 対策: フィルタリングしてから取得
const dirty = [85, NaN, 92, undefined, 78, null, 96];
const clean = dirty.filter(Number.isFinite);
console.log(Math.max(...clean)); // 96
console.log(Math.min(...clean)); // 78
Math.max() に NaN が 1 つでも含まれると結果は NaN になります。ユーザー入力や API レスポンスなど不正な値が混入する可能性がある場合は、必ずフィルタリングしてから使ってください。

オブジェクト配列から特定プロパティの最大値・最小値を取得する

map + Math.max
const products = [
  { name: "商品A", price: 500 },
  { name: "商品B", price: 1200 },
  { name: "商品C", price: 800 }
];

// map でプロパティを抽出してから Math.max
const maxPrice = Math.max(...products.map(p => p.price));
const minPrice = Math.min(...products.map(p => p.price));

console.log(`最高価格: ${maxPrice}`); // 1200
console.log(`最低価格: ${minPrice}`); // 500
reduce で最大値を持つオブジェクト自体を取得
const most = products.reduce((max, p) =>
  p.price > max.price ? p : max
);

console.log(most); // { name: "商品B", price: 1200 }
Math.max は値(数値)しか返しませんが、reduce なら最大値を持つオブジェクト自体を取得できます。「最高価格の商品名」が必要な場合は reduce を使いましょう。

最大値・最小値のインデックスを取得する

JavaScript
const scores = [85, 92, 78, 96, 88];

// 最大値のインデックス
const maxIndex = scores.indexOf(Math.max(...scores));
console.log(`最大値: ${scores[maxIndex]} (index: ${maxIndex})`); // 96 (index: 3)

// reduce で1回のループで取得(効率的)
const maxIdx = scores.reduce((best, val, i, arr) =>
  val > arr[best] ? i : best
, 0);
console.log(`最大値: ${scores[maxIdx]} (index: ${maxIdx})`); // 96 (index: 3)

N 番目に大きい値を取得する

JavaScript
function nthLargest(arr, n) {
  const sorted = [...arr].sort((a, b) => b - a);
  return sorted[n - 1]; // 1番目 = index 0
}

const scores = [85, 92, 78, 96, 88];
console.log(nthLargest(scores, 1)); // 96(1番大きい = 最大値)
console.log(nthLargest(scores, 2)); // 92(2番目に大きい)
console.log(nthLargest(scores, 3)); // 88(3番目に大きい)

重複を除いた N 番目

JavaScript
function nthLargestUnique(arr, n) {
  const unique = [...new Set(arr)].sort((a, b) => b - a);
  return unique[n - 1];
}

console.log(nthLargestUnique([96, 96, 92, 88, 85], 2)); // 92

実務でよく使うパターン

成績の最高点・最低点・平均点を一度に計算

JavaScript
function calcStats(scores) {
  if (scores.length === 0) return null;

  let min = Infinity, max = -Infinity, sum = 0;
  for (const s of scores) {
    if (s < min) min = s;
    if (s > max) max = s;
    sum += s;
  }

  return {
    min,
    max,
    avg: Math.round((sum / scores.length) * 10) / 10
  };
}

console.log(calcStats([85, 92, 78, 96, 88]));
// { min: 78, max: 96, avg: 87.8 }

日付の配列から最も古い日・最も新しい日を取得する

JavaScript
const dates = [
  new Date("2026-01-15"),
  new Date("2026-03-20"),
  new Date("2025-12-01"),
  new Date("2026-02-10")
];

// Date は数値に変換できるため Math.max / Math.min が使える
const newest = new Date(Math.max(...dates));
const oldest = new Date(Math.min(...dates));

console.log("最新:", newest.toLocaleDateString()); // 2026/3/20
console.log("最古:", oldest.toLocaleDateString()); // 2025/12/1

関連記事

よくある質問

QMath.max(…arr) で RangeError が出ます。
Aスプレッド構文は配列の全要素を関数の引数として展開するため、要素数が多すぎるとスタックオーバーフローが発生します。reduce または for ループに切り替えてください。目安として数千件を超える場合は reduce が安全です。
Qオブジェクト配列の特定プロパティの最大値を持つオブジェクトを取得するには?
Aarr.reduce((max, item) => item.value > max.value ? item : max) で最大値を持つオブジェクト自体を取得できます。Math.max は数値しか返さないため、オブジェクトが必要なら reduce を使います。
QNaN が混入している配列で最大値を取得すると NaN になります。
Aarr.filter(Number.isFinite) で NaN・undefined・null を除外してから Math.max を使ってください。
Q空配列で Math.max() を使うとどうなりますか?
AMath.max() は引数なしで -InfinityMath.min()Infinity を返します。空配列のチェック(arr.length > 0)を事前に入れてください。
Q2番目に大きい値を効率的に取得するには?
A全体をソートする方法([...arr].sort((a,b) => b-a)[1])が簡潔ですが、O(n log n) です。1 回のループで O(n) で取得するには、max と secondMax の 2 変数を使って for ループで更新します。

まとめ

配列から最小値・最大値を取得する方法を整理しました。

  • 基本: Math.max(...arr) / Math.min(...arr)(数千件以下)
  • 大規模配列: reduce(スタックオーバーフローなし)
  • 最速: for ループ(最小値と最大値を同時取得可能)
  • オブジェクト配列: map + Math.max(値のみ)/ reduce(オブジェクト自体)
  • NaN 対策: filter(Number.isFinite) で事前除外
  • インデックス: indexOf(Math.max(...)) または reduce で取得

成績処理、価格帯の算出、日付の範囲取得など、最大値・最小値の取得は実務の基本パターンです。配列のサイズに応じてスプレッド構文と reduce を使い分けてください。