数値配列を昇順にソートする
数値配列を昇順にソートする とは
Array.prototype.sort に比較関数を渡して、数値配列を正しく昇順・降順に並べる方法を学ぶ。
数値配列を昇順にソートする
JavaScript の Array.prototype.sort は、よく初心者がハマるメソッドの 1 つです。「数値配列をソートしたつもりが、なぜか [10, 2, 33, 4] が [10, 2, 33, 4] のような並びになってしまう」という経験は誰しもあります。これは sort が デフォルトで文字列として比較 するためです。数値を正しく並べるには、必ず 比較関数 を渡します。
ポイント
sortの鉄則は 「数値なら必ず比較関数を渡す」。デフォルトは文字列ソートになります。
比較関数なしの罠
まずは罠を体験してみましょう。比較関数を渡さない sort は、要素を 文字列化してから辞書順 で並べます。
JavaScript
const nums = [10, 2, 33, 4];
nums.sort();
console.log(nums); // 文字列比較で意図しない並びになる
// "10" は "2" より辞書順では小さい ("1" < "2") ため
// [10, 2, 33, 4] が並び替わって [10, 2, 33, 4] のように見える実際のところ "10" は "2" よりも辞書順では小さい ("1" < "2") ので、数値の昇順にはなりません。
比較関数で正しく数値ソート
比較関数は 2 引数 (a, b) を受け取り、負の数・0・正の数 を返します。
- 負の数を返したら
aをbより前 に並べる - 0 を返したら順序維持
- 正の数を返したら
aをbより後 に並べる
昇順 (小さい順) なら a - b を返すだけで OK です。
JavaScript
const nums = [10, 2, 33, 4];
const sorted = [...nums].sort((a, b) => a - b);
console.log(sorted); // [2, 4, 10, 33]降順 (大きい順) なら b - a です。
JavaScript
const desc = [...nums].sort((a, b) => b - a);
console.log(desc); // [33, 10, 4, 2]ポイント 「
a - bは昇順、b - aは降順」と覚える。マイナスが「前に出す」と読むのがコツです。
sort は破壊的
sort は配列を その場で並び替える破壊的メソッド です。元の配列をそのまま並べ替えてしまいます。
JavaScript
const nums = [3, 1, 2];
const sorted = nums.sort();
console.log(nums === sorted); // true (同じ配列を指している)元配列を保ちたいときは、先にスプレッドでコピーします。
JavaScript
const nums = [3, 1, 2];
const sorted = [...nums].sort((a, b) => a - b);
console.log(nums); // [3, 1, 2] そのまま
console.log(sorted); // [1, 2, 3] 新配列ES2023 以降は toSorted という非破壊版も追加されたので、新しいランタイムなら arr.toSorted((a, b) => a - b) も使えます。
動きを追ってみる
sort は要素を比較関数にペアで渡し、戻り値の符号で位置を決めていきます。
オブジェクト配列のソート
比較関数の真価はオブジェクト配列で発揮されます。年齢順、価格順、日付順、どれも同じパターンで書けます。
JavaScript
const users = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 22 },
];
users.sort((a, b) => a.age - b.age);
console.log(users[0].name); // "Bob"よくある間違い
第 1 に、sort() を比較関数なしで数値に使うのは前述の通り NG です。第 2 に、sort を呼ぶと元配列が並び替わってしまい、別の場所のコードに影響することがあります。コピーしてからソート が安全です。第 3 に、比較関数で true / false を返すコードを書いてしまう間違いがあります。return a > b は true / false ですが、sort は 0 / 正 / 負 を期待するので、Safari 等で安定しない動きをします。必ず数値を返す ようにします。
ポイント ソートは「比較関数 + 非破壊コピー」が定石。これだけで予期せぬバグが激減します。
やってみよう
数値配列 arr を受け取り、元配列を変更せずに 昇順ソート済みの新配列を返す sortAsc 関数を書きましょう。return [...arr].sort((a, b) => a - b) の 1 行で完成です。書けたら b - a に変えて降順版を作ったり、users のような配列を age 順に並べる練習もしてみましょう。
よくある質問
Q. ブラウザと Node.js で動作は変わりますか?
A. JavaScript の構文・組み込み機能(配列・文字列・Promise 等)はどちらでも同じです。違いは DOM API(ブラウザ専用)と fs などのファイル系(Node 専用)など、実行環境固有の機能です。コアロジックは両方で動くため、テストもしやすくなります。
Q. ES6 以降の新機能は使っても大丈夫ですか?
A. 現代のブラウザ・Node.js は ES2020 以降の機能をほぼサポートしています。古い IE 等を対象にする必要が無ければ、let/const、アロー関数、分割代入、async/await を積極的に使ってください。トランスパイル(Babel/Vite)が必要なケースは年々減っています。
Q. TypeScript に進む価値はありますか?
A. 型情報があるとリファクタやエディタ補完が劇的に効くため、規模が大きくなるなら TypeScript への移行を強くおすすめします。最初は any を許容しつつ徐々に型を付ければ、JS の知識をそのまま活かせます。
次のレッスン
次は Set で配列の重複を取り除く で、Array.prototype.sort に比較関数を渡して、数値配列を正しく昇順・降順に並べる方法を学ぶ を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 数値ソート の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 数値ソート とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- 比較関数
(a, b) => a - bを sort に渡すこと - 元配列を変更しないこと (
[...arr]でコピーしてからソート) - 昇順 (小さい順) で並べること
入出力例
test-cases.txt
sortAsc([10,2,33,4]) → [2,4,10,33]
sortAsc([3,1,2,3,1]) → [1,1,2,3,3]
sortAsc([-1,-10,5,0,2]) → [-10,-1,0,2,5]
sortAsc([]) → []