配列をソートするには
配列(リスト)を昇順・降順やキー指定で並べ替える基本形を各言語で示す。
破壊的か非破壊的か、JavaScript の既定が辞書順になる罠までを扱う。
公開:
Python 実行確認済み
nums = [3, 1, 10, 2]
print(sorted(nums)) # 新しいリストを返す → [1, 2, 3, 10]
nums.sort(reverse=True) # 元のリストをその場で降順に
words = ["banana", "apple"]
print(sorted(words, key=len)) # キー関数で基準を指定 → ['apple', 'banana']sorted は新しいリストを返し、list.sort は元のリストをその場で並べ替える。
並べ替えの基準を変えたいときは key に関数を渡し、降順にするなら reverse=True を指定する。
JavaScript 実行確認済み
const nums = [3, 1, 10, 2];
console.log([...nums].sort((a, b) => a - b)); // 数値順 → [1, 2, 3, 10]
console.log(nums.sort()); // 既定は文字列順 → [1, 10, 2, 3]Array.prototype.sort は比較関数を渡さないと要素を文字列に変換して比較するため、数値はそのままだと辞書順になる。
数値順にするには (a, b) => a - b を渡す。
sort は破壊的なので、元の配列を残すならスプレッドでコピーしてから並べ替える。
TypeScript 静的確認
const nums: number[] = [3, 1, 10, 2];
const asc: number[] = [...nums].sort((a, b) => a - b);
console.log(asc); // [1, 2, 3, 10]使い方は JavaScript と同じで、比較関数の引数と戻り値に型が付くだけである。
sort は元の配列を破壊的に並べ替えるため、number[] を保ちたいならスプレッドでコピーしてから呼ぶ。
Go 静的確認
package main
import (
"fmt"
"sort"
)
func main() {
nums := []int{3, 1, 10, 2}
sort.Ints(nums) // 昇順(破壊的)→ [1 2 3 10]
fmt.Println(nums)
sort.Slice(nums, func(i, j int) bool { return nums[i] > nums[j] }) // 任意の基準で降順
fmt.Println(nums)
}sort.Ints や sort.Strings は基本型のスライスをその場で昇順に並べ替える。
独自の基準や降順にするときは sort.Slice に比較関数を渡す。
いずれも元のスライスを破壊的に変更する。
つまずき
JavaScript の Array.prototype.sort は、比較関数を渡さないと要素を文字列に変換してから並べ替える。
そのため [3, 1, 10, 2] を既定の sort で並べ替えると、数値順の [1, 2, 3, 10] ではなく辞書順の [1, 10, 2, 3] になるという定番の罠がある。
数値を並べ替えるときは必ず (a, b) => a - b のような比較関数を渡す。
破壊的か非破壊的か
並べ替えには、元の配列をその場で変更する破壊的なもの(JavaScript の sort、Python の list.sort、Go の sort.Ints)と、新しい列を返す非破壊的なもの(Python の sorted)がある。
元の順序を後でも使うなら、破壊的な関数を呼ぶ前にコピーしておくと安全である。