配列を数値の大きさで並び替える

sort() は既定で文字列として比べるため、数値を渡すと [1, 10, 2] のように並びます。比較関数の書き方、元の配列を壊さない方法、日本語やオブジェクトの並び替えまでまとめます。

実行して検証済み処理系Node 22.22.3対応ES1難易度●●○○○目安9更新

答え

比較関数を渡します。 そして元の配列を壊さないように、先に複製します。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 1, 2, 5, 10, 100 ] [ 10, 1, 5, 100, 2 ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 100, 10, 5, 2, 1 ]

降順は b - a です。

javascript
const nums = [10, 1, 5, 100, 2];

console.log(nums.sort());
[ 1, 10, 100, 2, 5 ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1 と 3 を比べる → -2 2 と 1 を比べる → 1 2 と 3 を比べる → -1 2 と 1 を比べる → 1 [ 1, 2, 3 ]

なぜそのまま並べると狂うのか

sort() は、比較関数を渡さないと全部を文字列に変換してから比べます。

javascript
const nums = [3, 1, 2];

const sorted = nums.sort((a, b) => a - b);

console.log(sorted);
console.log(nums);
console.log(sorted === nums);
[ 1, 2, 3 ] [ 1, 2, 3 ] true
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 1, 2, 3 ] [ 1, 2, 3 ] [ 3, 1, 2 ]

文字列として並べると '10''2' より前になります。 1文字目の '1''2' を比べているからです。辞書順です。

仕様にもそう書いてあります。比較関数が undefined のとき、 要素を文字列に変換してから比べる、と定められています。

比較関数の決まり

比較関数は2つの値を受け取り、数値を返します。

返す値 意味
負の数 aにする
0 順序を変えない
正の数 a後ろにする

a - b が昇順になるのは、a のほうが小さいときに負の数になるからです。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 'apple', 'banana', 'cherry' ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 'あおき', 'さとう', 'ざっそう', 'たなか' ] [ 'あおき', 'ざっそう', 'さとう', 'たなか' ]

3件なのに4回比べています。同じ組を2回見てもいます。

どの順で何回比べるかは、仕様で決まっていません。 処理系に任されています。 比較関数はいつどう呼ばれても同じ答えを返すように書いてください。 中で数を数えたり、外の変数を書き換えたりすると結果が読めなくなります

真偽値を返してはいけません。 (a, b) => a > btrue / false になり、 数値に直すと 1 / 0 です。「前にする」を表せません

元の配列を壊さない

sort()破壊的メソッドです。呼んだ配列そのものを並び替えます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 'B', 'C', 'a', 'b' ] [ 'a', 'b', 'B', 'C' ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 'ゆうと(22)', 'あかり(30)', 'はると(41)' ]

戻り値は同じ配列です。別物ではありません。 元を残したいなら、次のどちらかにします。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 'あかり', 'ゆうと' ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 'a2', 'a3', 'b1' ]

toSorted()新しい配列を返す書き方です(ES2023)。 Node 20 / Chrome 110 / Safari 16 より前の環境では使えません。迷ったら、スプレッド構文で複製してから sort() を呼ぶほうが確実です。

文字列を並び替える

英数字だけなら比較関数は要りません。既定の辞書順で並びます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 1, 3, undefined ]
javascript
const nums = [3, NaN, 1, 2];

console.log([...nums].sort((a, b) => a - b));
[ 3, NaN, 1, 2 ]

日本語では期待どおりになりません。 文字コード順に並ぶためです。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 1, 2, 3 ]

「さとう」と「ざっそう」の順が入れ替わります

  • 既定 … (U+3055)と (U+3056)を別の文字として比べるので、 1文字目で決まってしまう
  • localeCompare濁った形として扱うので、 2文字目の で決まる。国語辞典と同じ並び

濁点・半角と全角・大文字と小文字が混ざると、こうした差が出ます。 日本語を並べるときは localeCompare を使ってください。

既定では大文字が全部先に来ます。ASCII では大文字(65〜)が小文字(97〜)より小さいためです。 localeCompare なら文字として同じものをまとめ、a b B C の順になります。

オブジェクトの配列を並び替える

比べたい値を取り出して、同じように書きます。

名前で並べるなら localeCompare です。

同じ値の順序は保たれる

比較関数が 0 を返した組は、元の並び順のままです(安定ソート。ES2019 以降は仕様で保証)。

a2a3 の順序が入れ替わりません。2段階で並べたいときに使えます (先に第2キーで並べ、次に第1キーで並べる)。

undefined は必ず最後に行く

undefined は比較関数に渡されません。問答無用で末尾に置かれます。

一方 NaN は渡されます。NaN との引き算は NaN になり、 比較関数が数値を返さないので並びが定まりません

並び替える前に弾いてください。

NaN の比較については なぜ NaN === NaN は false なのか にまとめてあります。

比較関数の決まり、安定ソートの保証、undefined の扱いは用語のページにまとめてあります。 → Array.prototype.sort() と toSorted()

この記事の根拠

  1. Array.prototype.sort — ECMAScript® 2026 Language Specificationtc39.es
  2. Array.prototype.toSorted — ECMAScript® 2026 Language Specificationtc39.es
  3. Array.prototype.sort() — MDNdeveloper.mozilla.org

掲載しているコード例は、公開前に読み手が押したときに動くのと同じもので実行して出力を突き合わせています。結果はリポジトリに残しています。

このページの原文(Markdown)