🧭

[JavaScript] 配列の最小値・最大値を求める

2024/11/19に公開3

目的

以下のように配列があったとして、その中で最も小さい値・最も大きい値を取り出したい。

[1, 3, 8, 7, 5]   // 最小値は1, 最大値は8

解決法

Array.reduce を使用する。

const arr = [1, 3, 8, 7, 5];

// Array.reduce に渡すコールバック関数
const getMin = (a, b) => Math.min(a, b);
const getMax = (a, b) => Math.max(a, b);

// 実際に求める
const min = arr.reduce(getMin);
const max = arr.reduce(getMax);

console.log(min, max);   // 1 8

解説

Array.reduce は、配列のそれぞれの要素に対して引数に渡されたコールバック関数を実行し、配列を「縮小」していく、JavaScript が提供する関数のひとつです。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

こういった、引数に関数を返す・もしくは関数を帰り値とする関数のことを 高階関数(こうかいかんすう) と呼びます。有名なものに mapfilter などがありますね。

さて、Array.reduce の動作のイメージを掴むため、簡単なサンプルを見てみます。以下は、配列の総和を求めるためのサンプルコードです。

const array1 = [1, 2, 4, 5];

const sumAll = array1.reduce(
  (sum, now) => sum + now
);

console.log(sumAll);   // 12

今回は、Array.reduce に以下のような関数が渡されているのがわかります。

(sum, now) => sum + now

Array.reduce は、まず配列の左から2つを取ってコールバック関数に代入します。今回の場合、sum1now2 ですね。

(sum, now) => 1 + 2

当然、結果は 3 となります。ここからが重要で、二回目以降は 前回の結果と次の値 を引数として代入します。ここでいう「前回の結果」は 3、「次の値」は 4 になるので、以下のようになりますね。

(sum, now) => 3 + 4

結果は 7。次の値は 5 なので、以下のようになります。

(sum, now) => 7 + 5

結果は 12 ですね。
次の値がなくなれば、Array.reduce は処理を止め、結果を返します。そのため、答えとして 12 が返るわけです。

このように、最終的に単一の値が返るため「縮小」(reduce)なんですね。


ここまでを踏まえて、最大値・最小値のコードを見ます。

const arr = [1, 3, 8, 7, 5];

// Array.reduce に渡すコールバック関数
const getMin = (a, b) => Math.min(a, b);
const getMax = (a, b) => Math.max(a, b);

// 実際に求める
const min = arr.reduce(getMin);
const max = arr.reduce(getMax);

console.log(min, max);   // 1 8

重要なのはここですね。

// Array.reduce に渡すコールバック関数
const getMin = (a, b) => Math.min(a, b);
const getMax = (a, b) => Math.max(a, b);

さきほどのイメージに当てはめると、「配列の中の要素を次々に Math.min もしくは Math.max に代入する操作」 ということがわかります。Math.minMath.max はそれぞれ与えられた引数の中で最も小さい・大きい数値を返す関数なので、 「配列の要素を2つずつ比較して、より小さい・大きい方を残す」 という操作だといえます。

Progate Path コミュニティ

Discussion

junerjuner
よつよつ

コメントありがとうございます🫶

配列のサイズが小規模であると断定できる場合は、ご指摘の通りスプレッド構文が有効ですね!
ただし、実行環境によっては関数の引数の数に上限が設けられる場合があります。こういった場合Array.reduce のほうが有効であるため、最もつつがない方法として取り上げています

しかし、スプレッド構文の (...) と apply のどちらも、配列に膨大な要素があった場合は、配列の要素を関数の引数として渡そうとするため、失敗したり、誤った結果を返したりすることがあります。~ reduce の方法はこの問題が発生しません。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/max