- PHP
PHP配列ソート関数一覧 sort・usort・asort・ksortの違い
PHPの配列ソート関数は、「値で並べるかキーで並べるか」「キーを維持するか」「比較を自分で書くか」の3点で選べます。 値で並べてキーを振り直すなら sort、キーを維持するなら asort、キーで並べるなら ksort、比較のルールを自分で決めたいなら頭に u が付く usort・uasort・uksort です。
この記事では、全ソート関数を1枚の早見表にまとめ、PHP 8.4.21 で実行した出力をそのまま載せています。多次元配列を複数のキーで並べ替える書き方、array_multisort との使い分け、日本語や数値文字列の並び替え、PHP 8 系で変わった点まで、コピーして使える形で確認できます。
PHPソート関数の早見表
| 関数 | 並べ替えの対象 | キーの扱い | 順序 | 比較方法 |
|---|---|---|---|---|
sort |
値 | 0 から振り直す | 昇順 | 標準の比較(フラグで変更可) |
rsort |
値 | 0 から振り直す | 降順 | 標準の比較(フラグで変更可) |
usort |
値 | 0 から振り直す | 自由 | 自作の比較関数 |
asort |
値 | 維持する | 昇順 | 標準の比較(フラグで変更可) |
arsort |
値 | 維持する | 降順 | 標準の比較(フラグで変更可) |
uasort |
値 | 維持する | 自由 | 自作の比較関数 |
ksort |
キー | 維持する | 昇順 | 標準の比較(フラグで変更可) |
krsort |
キー | 維持する | 降順 | 標準の比較(フラグで変更可) |
uksort |
キー | 維持する | 自由 | 自作の比較関数 |
natsort |
値 | 維持する | 昇順 | 自然順(大文字と小文字を区別) |
natcasesort |
値 | 維持する | 昇順 | 自然順(大文字と小文字を区別しない) |
array_multisort |
値(複数の配列を連動) | 文字列キーは維持、数値キーは振り直す | 配列ごとに指定 | 標準の比較(フラグで変更可) |
shuffle |
値 | 0 から振り直す | ランダム | — |
array_reverse |
並びを逆にするだけ | 数値キーは振り直す(第2引数で維持可) | 逆順 | —(新しい配列を返す) |
名前の読み方:a は連想(associative)=キー維持、k はキー(key)、r は逆順(reverse)、u はユーザー定義(user)です。この4文字の組み合わせで、どの関数かを思い出せます。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「PHP配列ソート関数一覧 sort・usort・asort・ksortの違い」
やりたいことから選ぶ逆引き表
| やりたいこと | 書き方 |
|---|---|
| 数値や文字列の配列を小さい順に | sort($a); |
| 大きい順に | rsort($a); |
| 連想配列を値で並べ、キーは残す | asort($a); / arsort($a); |
| 連想配列をキーで並べる | ksort($a); / krsort($a); |
| 多次元配列を特定の列で並べる | usort($rows, fn($a, $b) => $a['price'] <=> $b['price']); |
| 複数の列で並べる | usort($rows, fn($a, $b) => [$a['x'], $a['y']] <=> [$b['x'], $b['y']]); |
img2 を img10 より前に |
sort($a, SORT_NATURAL | SORT_FLAG_CASE); |
| 大文字と小文字を区別せずに | sort($a, SORT_STRING | SORT_FLAG_CASE); |
| 数字の文字列を文字として並べる | sort($a, SORT_STRING); |
| 日本語を五十音順に | (new Collator('ja_JP'))->sort($a); |
| 元の配列を変えずに並べた結果がほしい | コピーしてからソート(後述) |
| 上位3件だけ取り出す | arsort($a); array_slice($a, 0, 3, true); |
共通の注意:配列そのものを書き換え、戻り値はtrue
ソート関数は引数の配列を直接並べ替えます(参照渡し)。戻り値は並べ替えた配列ではなく true です。
<?php
$x = [3, 1, 2];
$y = sort($x);
var_dump($y);
bool(true)
foreach (sort($x) as $v) のように戻り値を使うと、次の警告になります。
Warning: foreach() argument must be of type array|object, true given
sort($x); と1行で実行し、その後で $x を使う形にします。PHP の公式マニュアル(sort のページ)を開いて確認したところ、PHP 8.2.0 から戻り値の型が bool から true に変わったと記載されています。
基本の6関数:sort・rsort・asort・arsort・ksort・krsort
同じ連想配列を6つの関数に渡して、結果を比べます。
<?php
$base = ['b' => 3, 'a' => 1, 'd' => 10, 'c' => 2];
foreach (['sort', 'rsort', 'asort', 'arsort', 'ksort', 'krsort'] as $f) {
$x = $base;
$f($x);
echo "== $f\n";
print_r($x);
}
実行結果(PHP 8.4.21。print_r の改行は詰めています):
== sort
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 10 )
== rsort
Array ( [0] => 10 [1] => 3 [2] => 2 [3] => 1 )
== asort
Array ( [a] => 1 [c] => 2 [b] => 3 [d] => 10 )
== arsort
Array ( [d] => 10 [b] => 3 [c] => 2 [a] => 1 )
== ksort
Array ( [a] => 1 [b] => 3 [c] => 2 [d] => 10 )
== krsort
Array ( [d] => 10 [c] => 2 [b] => 3 [a] => 1 )
| 関数 | 結果の読み方 |
|---|---|
sort / rsort |
値で並び、キー a〜d が 0〜3 に置き換わる |
asort / arsort |
値で並び、キーと値の組はそのまま |
ksort / krsort |
キーの順に並ぶ。値は見ていない |
連想配列に sort を使うとキーがなくなります。 「名前 => 点数」のような配列を値で並べるときは asort・arsort を選びます。
上位N件を取り出す
<?php
$scores = ['tanaka' => 80, 'sato' => 95, 'abe' => 80, 'ito' => 60];
arsort($scores);
print_r(array_slice($scores, 0, 3, true));
Array ( [sato] => 95 [tanaka] => 80 [abe] => 80 )
array_slice の第4引数を true にすると、数値キーの場合も含めてキーが維持されます。同点の tanaka と abe は、元の配列での順番どおりに並んでいます(PHP 8.0 以降の安定ソート。後述します)。
usort・uasort・uksort:比較ルールを自分で書く
比較関数は、2つの要素を受け取り「負の数・0・正の数」のいずれかを返す関数です。 負なら1つ目が前、正なら2つ目が前、0 なら同順位です。
PHP 7.0 で入った宇宙船演算子と、PHP 7.4 で入ったアロー関数を使うと、1行で書けます。
<?php
$base = ['b' => 3, 'a' => 1, 'd' => 10, 'c' => 2];
$x = $base;
usort($x, fn($p, $q) => $p <=> $q); // 値の昇順、キーは振り直す
print_r($x);
$x = $base;
uasort($x, fn($p, $q) => $q <=> $p); // 値の降順、キーは維持
print_r($x);
$x = $base;
uksort($x, fn($p, $q) => strcmp($q, $p)); // キーの降順
print_r($x);
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 10 )
Array ( [d] => 10 [b] => 3 [c] => 2 [a] => 1 )
Array ( [d] => 10 [c] => 2 [b] => 3 [a] => 1 )
| 式 | 返す値 | 意味 |
|---|---|---|
$a <=> $b |
-1 / 0 / 1 | 昇順 |
$b <=> $a |
-1 / 0 / 1 | 降順(左右を入れ替えるだけ) |
strcmp($a, $b) |
負 / 0 / 正 | 文字列として比較 |
strcasecmp($a, $b) |
負 / 0 / 正 | 大文字と小文字を区別しない |
strnatcmp($a, $b) |
-1 / 0 / 1 | 自然順 |
version_compare($a, $b) |
-1 / 0 / 1 | バージョン番号として比較 |
比較関数は整数を返す
比較関数で $a > $b のように真偽値を返したり、小数の引き算をそのまま返したりすると、意図した並びにならないことがあります。
エラーになる例(真偽値を返している)
<?php
$x = [3, 1, 2];
usort($x, fn($a, $b) => $a > $b);
Deprecated: usort(): Returning bool from comparison function is deprecated, return an integer less than, equal to, or greater than zero
意図どおりに並ばない例(小数の引き算)
<?php
$x = [0.5, 0.2, 0.9, 0.1];
usort($x, fn($a, $b) => $a - $b);
echo json_encode($x), "\n";
usort($x, fn($a, $b) => $a <=> $b);
echo json_encode($x), "\n";
[0.5,0.2,0.9,0.1]
[0.1,0.2,0.5,0.9]
1つ目は並び替わっていません。比較関数の戻り値は整数として扱われるため、0.3 や -0.4 といった差が 0(同順位)とみなされたためです。数値の比較は引き算ではなく <=> を使うと、整数・小数・文字列のどれでも正しく -1 / 0 / 1 が返ります。
多次元配列を並べ替える
ここからは、次の備品データを使います。
<?php
$items = [
['id' => 1, 'name' => 'ノート', 'category' => '文具', 'price' => 300, 'stock' => 12],
['id' => 2, 'name' => 'マウス', 'category' => 'PC', 'price' => 1800, 'stock' => 5],
['id' => 3, 'name' => 'ペン', 'category' => '文具', 'price' => 120, 'stock' => 40],
['id' => 4, 'name' => 'キーボード', 'category' => 'PC', 'price' => 1800, 'stock' => 3],
['id' => 5, 'name' => '付箋', 'category' => '文具', 'price' => 300, 'stock' => 8],
];
function show(array $rows): void {
foreach ($rows as $k => $r) {
echo "[$k] ", json_encode($r, JSON_UNESCAPED_UNICODE), "\n";
}
}
1つの列で並べる
usort($items, fn($a, $b) => $a['price'] <=> $b['price']);
show($items);
[0] {"id":3,"name":"ペン","category":"文具","price":120,"stock":40}
[1] {"id":1,"name":"ノート","category":"文具","price":300,"stock":12}
[2] {"id":5,"name":"付箋","category":"文具","price":300,"stock":8}
[3] {"id":2,"name":"マウス","category":"PC","price":1800,"stock":5}
[4] {"id":4,"name":"キーボード","category":"PC","price":1800,"stock":3}
降順にするには $b['price'] <=> $a['price'] と左右を入れ替えます。同じ価格のノート(id 1)と付箋(id 5)は、元の順番のまま並んでいます。
複数の列で並べる:配列どうしを比較する
「カテゴリの昇順 → 価格の降順 → 在庫の昇順」のような複数キーのソートは、配列どうしを <=> で比べると1行で書けます。 配列の比較は先頭の要素から順に行われ、差が出たところで結果が決まります。
usort($items, fn($a, $b) =>
[$a['category'], $b['price'], $a['stock']]
<=>
[$b['category'], $a['price'], $b['stock']]
);
show($items);
[0] {"id":4,"name":"キーボード","category":"PC","price":1800,"stock":3}
[1] {"id":2,"name":"マウス","category":"PC","price":1800,"stock":5}
[2] {"id":5,"name":"付箋","category":"文具","price":300,"stock":8}
[3] {"id":1,"name":"ノート","category":"文具","price":300,"stock":12}
[4] {"id":3,"name":"ペン","category":"文具","price":120,"stock":40}
降順にしたい列だけ、左右の配列で $a と $b を入れ替えるのがコツです(上の例では price)。
複数の列で並べる:エルビス演算子でつなぐ
もう1つの書き方は、比較結果が 0(同順位)のときだけ次の比較に進む形です。
usort($items, fn($a, $b) =>
strcmp($a['category'], $b['category'])
?: $b['price'] <=> $a['price']
?: $a['stock'] <=> $b['stock']
);
結果は上と同じ並びになりました。列ごとに strcmp や strnatcmp など比較方法を変えたいときは、こちらの書き方が向いています。
| 書き方 | 向いている場面 | 20万件での所要時間(手元の計測) |
|---|---|---|
配列どうしの <=> |
列が多く、読みやすさを優先したい | 0.67 秒 |
?: でつなぐ |
列ごとに比較関数を変えたい、少しでも速くしたい | 0.39 秒 |
array_multisort |
件数が多く、標準の比較で足りる | 0.11 秒 |
(2列の整数キーで 20 万件を並べ替えた1回の計測値です。環境やデータによって変わるので、傾向の目安としてご覧ください。)
キーを維持して並べる
行のキーに意味がある場合(ID をキーにしている等)は uasort を使います。
uasort($items, fn($a, $b) => $a['price'] <=> $b['price']);
show($items);
[2] {"id":3,"name":"ペン","category":"文具","price":120,"stock":40}
[0] {"id":1,"name":"ノート","category":"文具","price":300,"stock":12}
[4] {"id":5,"name":"付箋","category":"文具","price":300,"stock":8}
[1] {"id":2,"name":"マウス","category":"PC","price":1800,"stock":5}
[3] {"id":4,"name":"キーボード","category":"PC","price":1800,"stock":3}
比較関数を使い回す
列名と向きを引数に取り、比較関数を返す関数を作っておくと、呼び出し側が短くなります。
<?php
function by(string $key, bool $desc = false): Closure {
return fn($a, $b) => $desc ? $b[$key] <=> $a[$key] : $a[$key] <=> $b[$key];
}
$items = [['id' => 1, 'price' => 300], ['id' => 2, 'price' => 1800], ['id' => 3, 'price' => 120]];
usort($items, by('price', true));
echo json_encode(array_column($items, 'id')), "\n";
[2,1,3]
オブジェクトの配列を並べる
オブジェクトでも書き方は同じです。DateTimeImmutable どうしは <=> で比較できます。
<?php
final class Task {
public function __construct(
public string $title,
public int $priority,
public DateTimeImmutable $due,
) {}
}
$tasks = [
new Task('B', 2, new DateTimeImmutable('2026-10-05')),
new Task('A', 1, new DateTimeImmutable('2026-10-09')),
new Task('C', 2, new DateTimeImmutable('2026-10-01')),
];
// 優先度の高い順 → 期限の早い順
usort($tasks, fn(Task $a, Task $b) => [$b->priority, $a->due] <=> [$a->priority, $b->due]);
foreach ($tasks as $t) {
echo $t->title, ' p', $t->priority, ' ', $t->due->format('Y-m-d'), "\n";
}
C p2 2026-10-01
B p2 2026-10-05
A p1 2026-10-09
決まった順番・nullを最後に・文字数順
<?php
// 1) 自分で決めた順番(high → mid → low)
$order = ['high' => 0, 'mid' => 1, 'low' => 2];
$x = ['low', 'high', 'mid', 'high'];
usort($x, fn($a, $b) => $order[$a] <=> $order[$b]);
echo json_encode($x), "\n";
// 2) null を最後に回す
$x = [3, null, 1, null, 2];
usort($x, fn($a, $b) => [$a === null, $a] <=> [$b === null, $b]);
echo json_encode($x), "\n";
// 3) 文字数の短い順 → 同じ長さなら文字順
$w = ['banana', 'fig', 'apple', 'kiwi'];
usort($w, fn($a, $b) => [strlen($a), $a] <=> [strlen($b), $b]);
echo json_encode($w), "\n";
["high","high","mid","low"]
[1,2,3,null,null]
["fig","kiwi","apple","banana"]
日本語の文字数で比べるときは strlen(バイト数)ではなく mb_strlen を使います。
元の配列を変えずに、並べた結果を受け取る
PHP の配列は値渡しでコピーされるので、関数の中でソートして返せば、元の配列はそのまま残ります。
<?php
function sorted(array $a, callable $cmp): array {
usort($a, $cmp);
return $a;
}
$original = [3, 1, 2];
$result = sorted($original, fn($a, $b) => $a <=> $b);
echo json_encode([$original, $result]), "\n";
[[3,1,2],[1,2,3]]
array_multisortとarray_columnの使い分け
array_multisort は、複数の配列を「連動させて」並べ替える関数です。 最初の配列で並べ、同じ値のところは次の配列で比べ、最後に渡した配列まで同じ順に並べ替えます。
<?php
$names = ['c', 'a', 'b'];
$scores = [70, 90, 80];
array_multisort($scores, SORT_DESC, $names);
echo json_encode([$scores, $names]), "\n";
[[90,80,70],["a","b","c"]]
多次元配列では、array_column で列を取り出して並べ替えの基準にします。
array_multisort(
array_column($items, 'category'), SORT_ASC, SORT_STRING,
array_column($items, 'price'), SORT_DESC, SORT_NUMERIC,
$items
);
show($items);
[0] {"id":2,"name":"マウス","category":"PC","price":1800,"stock":5}
[1] {"id":4,"name":"キーボード","category":"PC","price":1800,"stock":3}
[2] {"id":1,"name":"ノート","category":"文具","price":300,"stock":12}
[3] {"id":5,"name":"付箋","category":"文具","price":300,"stock":8}
[4] {"id":3,"name":"ペン","category":"文具","price":120,"stock":40}
array_multisortで知っておきたい2点
1. 配列の長さがそろっていないとエラーになります。
ValueError: Array sizes are inconsistent
2. 基準の列が同じ値のとき、次に渡した配列(行そのもの)で比較されます。 元の順番が保たれるわけではありません。
<?php
$data = [['n' => 'b', 'v' => 2], ['n' => 'a', 'v' => 2], ['n' => 'c', 'v' => 1]];
array_multisort(array_column($data, 'v'), SORT_ASC, $data);
echo json_encode(array_column($data, 'n')), "\n"; // array_multisort
$data = [['n' => 'b', 'v' => 2], ['n' => 'a', 'v' => 2], ['n' => 'c', 'v' => 1]];
usort($data, fn($a, $b) => $a['v'] <=> $b['v']);
echo json_encode(array_column($data, 'n')), "\n"; // usort
["c","a","b"]
["c","b","a"]
v が同じ 2 件について、usort は元の順(b → a)を保ち、array_multisort は行どうしを比べて a → b に並べました。同順位のときの並びまで決めたい場合は、基準の列を明示的に追加すると結果が安定します。
| 観点 | usort + <=> |
array_multisort + array_column |
|---|---|---|
| 読みやすさ | 比較の内容が1か所にまとまる | 列・向き・フラグを並べて書く |
| 比較の自由度 | 高い(関数を自由に書ける) | 標準の比較とフラグの範囲 |
| 同順位の扱い | 元の順番を保つ | 次に渡した配列で比較 |
| 速度(手元の20万件) | 0.39〜0.67 秒 | 0.11 秒 |
| キー | 振り直す(uasort なら維持) |
文字列キーは維持、数値キーは振り直す |
ふだんは usort、件数が多くて速度を優先したいときは array_multisort という選び方がおすすめです。
array_columnで「キー => 値」にしてからソートする
array_column の第3引数でキーにする列を指定すると、asort や ksort がそのまま使える形になります。
$prices = array_column($items, 'price', 'name'); // 名前 => 価格
asort($prices);
echo json_encode($prices, JSON_UNESCAPED_UNICODE), "\n";
$byId = array_column($items, null, 'id'); // id => 行全体
krsort($byId);
echo json_encode(array_keys($byId)), "\n";
{"ペン":120,"ノート":300,"付箋":300,"マウス":1800,"キーボード":1800}
[5,4,3,2,1]
ソートフラグ:数値文字列・自然順・大文字小文字
sort・rsort・asort・arsort・ksort・krsort・array_multisort は、第2引数(array_multisort は各配列の後ろ)にフラグを渡して比較方法を変えられます。フラグの一覧は公式マニュアルの sort のページで確認しました。
| フラグ | 比較方法 |
|---|---|
SORT_REGULAR(既定) |
通常の比較演算子と同じ |
SORT_NUMERIC |
数値として比較 |
SORT_STRING |
文字列として比較 |
SORT_LOCALE_STRING |
現在のロケール(setlocale)に基づいて文字列比較 |
SORT_NATURAL |
自然順(natsort と同じ並び) |
SORT_FLAG_CASE |
SORT_STRING か SORT_NATURAL と組み合わせて、大文字と小文字を区別しない |
数字の文字列を並べる
<?php
$n = ['10', '9', '2', '1'];
$x = $n; sort($x); print_r($x);
$x = $n; sort($x, SORT_STRING); print_r($x);
$x = $n; sort($x, SORT_NUMERIC); print_r($x);
Array ( [0] => 1 [1] => 2 [2] => 9 [3] => 10 ) ← 既定
Array ( [0] => 1 [1] => 10 [2] => 2 [3] => 9 ) ← SORT_STRING
Array ( [0] => 1 [1] => 2 [2] => 9 [3] => 10 ) ← SORT_NUMERIC
数字だけの文字列どうしは、既定でも数値として比較されます。 郵便番号や型番のように「文字として」並べたいときは SORT_STRING を指定します。
既定の比較では '1e1'・'10'・'010'・'10.0' がすべて同じ値とみなされる点も覚えておくと役立ちます(手元では '1e3' == '1000' が true でした)。コードや ID を並べるときは SORT_STRING を付けておくと、見た目どおりの文字順になります。
ファイル名を自然順に並べる
<?php
$f = ['img12.png', 'img10.png', 'IMG2.png', 'img1.png'];
$x = $f; sort($x); print_r($x);
$x = $f; sort($x, SORT_NATURAL); print_r($x);
$x = $f; sort($x, SORT_NATURAL | SORT_FLAG_CASE); print_r($x);
$x = $f; natsort($x); print_r($x);
$x = $f; natcasesort($x); print_r($x);
Array ( [0] => IMG2.png [1] => img1.png [2] => img10.png [3] => img12.png ) ← sort
Array ( [0] => IMG2.png [1] => img1.png [2] => img10.png [3] => img12.png ) ← SORT_NATURAL
Array ( [0] => img1.png [1] => IMG2.png [2] => img10.png [3] => img12.png ) ← SORT_NATURAL | SORT_FLAG_CASE
Array ( [2] => IMG2.png [3] => img1.png [1] => img10.png [0] => img12.png ) ← natsort
Array ( [3] => img1.png [2] => IMG2.png [1] => img10.png [0] => img12.png ) ← natcasesort
| 書き方 | 自然順 | 大文字小文字 | キー |
|---|---|---|---|
sort($a, SORT_NATURAL) |
する | 区別する(大文字が先) | 振り直す |
sort($a, SORT_NATURAL | SORT_FLAG_CASE) |
する | 区別しない | 振り直す |
natsort($a) |
する | 区別する | 維持する |
natcasesort($a) |
する | 区別しない | 維持する |
natsort はキーを維持するので、foreach で回すと並べ替えた順に出てきますが、$x[0] は元の先頭要素のままです。添字でアクセスしたいときは sort($a, SORT_NATURAL | SORT_FLAG_CASE) を使うか、array_values でキーを振り直します。
バージョン番号を並べる
<?php
$v = ['v1.10', 'v1.9', 'v1.2'];
sort($v); echo json_encode($v), "\n";
sort($v, SORT_NATURAL); echo json_encode($v), "\n";
usort($v, 'version_compare'); echo json_encode($v), "\n";
["v1.10","v1.2","v1.9"]
["v1.2","v1.9","v1.10"]
["v1.2","v1.9","v1.10"]
大文字と小文字を区別せずに並べる
<?php
$x = ['banana', 'apple', 'Cherry'];
sort($x); print_r($x);
sort($x, SORT_STRING | SORT_FLAG_CASE); print_r($x);
Array ( [0] => Cherry [1] => apple [2] => banana )
Array ( [0] => apple [1] => banana [2] => Cherry )
既定では文字コード順なので、大文字が小文字より先に並びます。
日付の文字列を並べる
2026-10-03 のようにゼロ埋めされた形式は、文字列としてそのまま並べられます。ゼロ埋めされていない値が混ざる場合は、日付に変換して比べます。
<?php
$d = ['2026-10-03', '2026-9-30', '2026-10-01'];
sort($d);
echo json_encode($d), "\n";
usort($d, fn($a, $b) => strtotime($a) <=> strtotime($b));
echo json_encode($d), "\n";
["2026-10-01","2026-10-03","2026-9-30"]
["2026-9-30","2026-10-01","2026-10-03"]
日本語を並べる:Collatorと読みがな
sort で日本語を並べると、文字コード(UTF-8 のバイト列)の順になります。
<?php
$j = ['佐藤', '鈴木', '阿部', 'さとう', 'アベ', 'すずき', '田中'];
$x = $j;
sort($x);
echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";
["さとう","すずき","アベ","佐藤","田中","鈴木","阿部"]
ひらがな → カタカナ → 漢字の順になり、「アベ」が「すずき」の後ろに来ています。
intl拡張のCollatorで五十音順にする
ひらがなとカタカナを混ぜて五十音順に並べたいときは、intl 拡張の Collator が使えます(php -m に intl が表示されていれば利用できます。手元は ICU 74.2)。
<?php
$j = ['佐藤', '鈴木', '阿部', 'さとう', 'アベ', 'すずき', '田中'];
$c = new Collator('ja_JP');
$x = $j;
$c->sort($x); // キーを振り直す
echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";
$x = ['b' => 'すずき', 'a' => 'アベ', 'c' => 'さとう'];
$c->asort($x); // キーを維持
echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";
// 多次元配列では compare を比較関数に使う
$rows = [['n' => 'すずき'], ['n' => 'アベ'], ['n' => 'さとう']];
usort($rows, fn($a, $b) => $c->compare($a['n'], $b['n']));
echo json_encode($rows, JSON_UNESCAPED_UNICODE), "\n";
["アベ","さとう","すずき","阿部","佐藤","田中","鈴木"]
{"a":"アベ","c":"さとう","b":"すずき"}
[{"n":"アベ"},{"n":"さとう"},{"n":"すずき"}]
かなは「アベ → さとう → すずき」と五十音順になりました。漢字は読みではなく、文字ごとに定められた順で並びます(阿部 → 佐藤 → 田中 → 鈴木)。プログラムは「佐藤」の読みを知らないためです。
Collator には数字を数値として扱う設定もあります。
$c2 = new Collator('en');
$c2->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
$x = ['file10', 'file9', 'File2'];
$c2->sort($x);
echo json_encode($x), "\n";
["File2","file9","file10"]
漢字の名前は「読みがな」の列で並べる
漢字を読みの順に並べたいときは、読みがなの列を別に持ち、その列で並べるのが確実です。
<?php
$members = [
['name' => '佐藤', 'kana' => 'サトウ'],
['name' => '阿部', 'kana' => 'アベ'],
['name' => '鈴木', 'kana' => 'スズキ'],
];
usort($members, fn($a, $b) => strcmp($a['kana'], $b['kana']));
echo json_encode(array_column($members, 'name'), JSON_UNESCAPED_UNICODE), "\n";
["阿部","佐藤","鈴木"]
読みがなをカタカナ(またはひらがな)に統一しておけば、strcmp だけで五十音順になります。
SORT_LOCALE_STRINGを使う場合
SORT_LOCALE_STRING は、setlocale で設定したロケールの規則で並べます。ドイツ語のロケール(de_DE.utf8)で試した結果です。
<?php
setlocale(LC_COLLATE, 'de_DE.utf8');
$g = ['Zebra', 'Äpfel', 'Apfel', 'Öl'];
$x = $g; sort($x); echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";
$x = $g; sort($x, SORT_LOCALE_STRING); echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";
["Apfel","Zebra","Äpfel","Öl"]
["Apfel","Äpfel","Öl","Zebra"]
結果はサーバーにインストールされているロケールに左右されます。環境が変わっても同じ結果にしたい場合は Collator のほうが扱いやすいでしょう。
PHP 8系で変わった点
| バージョン | 変更点 | 確認方法 |
|---|---|---|
| 7.0 | 宇宙船演算子 <=> が使える |
一般に知られた仕様(PHP 7 では未実行) |
| 7.4 | アロー関数 fn() => が使える |
一般に知られた仕様(PHP 7 では未実行) |
| 8.0 | ソートが安定になった(同順位の要素は元の順番を保つ) | 公式マニュアルの sort のページ+8.4.21 で実行 |
| 8.0 | 数値と、数値でない文字列の比較方法が変わった | 公式の 8.0 移行ガイド+8.4.21 で実行 |
| 8.2 | sort などの戻り値の型が bool から true に |
公式マニュアルの sort のページ |
この記事の実行結果はすべて PHP 8.4.21 のものです。PHP 7 系の挙動は手元では未実行で、公式マニュアルと移行ガイドの記載にもとづいています。
PHP 8.0から安定ソートになった
安定ソートとは、比較して同順位になった要素が、元の配列での順番を保つソートのことです。 公式マニュアルには「PHP 8.0.0 より前は、同順位の要素の相対的な順序は未定義だった」と書かれています。
// 価格で並べる:同じ 300 の id 1 と 5、同じ 1800 の id 2 と 4 は元の順のまま
usort($items, fn($a, $b) => $a['price'] <=> $b['price']);
echo implode(',', array_column($items, 'id')), "\n";
3,1,5,2,4
1,000 件のデータで「同じキーの要素が元の順番どおりか」を調べるコードも実行し、すべて元の順番が保たれていることを確かめました。
安定ソートのおかげで、「優先度の低いキーから順に、2回ソートする」という書き方もできます。
usort($items, fn($a, $b) => $a['stock'] <=> $b['stock']); // 先に在庫順
usort($items, fn($a, $b) => $a['category'] <=> $b['category']); // 次にカテゴリ順
echo implode(',', array_column($items, 'id')), "\n";
4,2,5,1,3
カテゴリごとにまとまり、その中は在庫の少ない順になっています。PHP 7 系でも動かすコードでは、同順位の順番に頼らず、複数キーを1つの比較関数に書いておくと結果がそろいます。
数値と文字列の比較が変わった
PHP 8.0 の移行ガイドによると、数値と「数値でない文字列」を比べるとき、PHP 8.0 以降は数値のほうを文字列に変換して比較します(PHP 7 系では文字列のほうを数値に変換していました)。
| 比較 | PHP 7 系(移行ガイドの記載) | PHP 8.0 以降(8.4.21 で実行) |
|---|---|---|
0 == "foo" |
true | false |
0 == "" |
true | false |
42 == "42foo" |
true | false |
0 == "0" |
true | true |
42 == " 42" |
true | true |
ソートは内部で同じ比較を使うので、数値と文字列が混ざった配列の並びに影響します。PHP 8.4.21 での結果です。
<?php
$m = [10, '9', 'abc', 2, '1e1', '10'];
$x = $m; sort($x); print_r($x);
$x = $m; sort($x, SORT_STRING); print_r($x);
Array ( [0] => 2 [1] => 9 [2] => 10 [3] => 1e1 [4] => 10 [5] => abc )
Array ( [0] => 10 [1] => 10 [2] => 1e1 [3] => 2 [4] => 9 [5] => abc )
var_dump(0 <=> 'foo'); // int(-1) 0 は "foo" より前
var_dump('abc' <=> 5); // int(1) "abc" は 5 より後ろ
var_dump('10' <=> '9'); // int(1) 数字どうしは数値として比較
var_dump('10' <=> '9a'); // int(-1) 片方が数値でなければ文字列として比較
PHP 8 系では、数値でない文字列は数値より後ろに並びます。公式マニュアルも「型が混ざった配列を既定のフラグでソートするときは注意」と案内しています。型が混ざる可能性がある配列は、SORT_STRING か SORT_NUMERIC を明示するか、usort で比較方法を決めておくと、バージョンによらず同じ結果になります。
つまずきやすい点と直し方
| 症状 | 原因 | 直し方 |
|---|---|---|
$sorted = sort($a) が true になる |
戻り値は並べ替え後の配列ではない | sort($a); の後で $a を使う |
| 連想配列のキーが 0,1,2 になった | sort・usort はキーを振り直す |
asort・uasort を使う |
img10 が img2 より前に来る |
文字コード順で比べている | SORT_NATURAL か natsort |
| 小数の配列が並び替わらない | 比較関数で引き算の結果を返している | <=> を使う |
| Deprecated: Returning bool ... | 比較関数が真偽値を返している | <=> で整数を返す |
natsort の後に $a[0] が先頭にならない |
キーが維持されている | array_values($a) で振り直す |
| ひらがなとカタカナが別々に並ぶ | 文字コード順で比べている | Collator か、読みがなの列で並べる |
'1e1' と '10' が同じ扱いになる |
数値文字列として比較されている | SORT_STRING を指定 |
| ValueError: Array sizes are inconsistent | array_multisort に渡した配列の長さが違う |
array_column の結果の件数を確認 |
よくある質問
Q. sort と usort はどちらを使えばよいですか?
A. 数値や文字列だけの配列を昇順・降順に並べるなら sort・rsort が簡潔です。多次元配列の特定の列で並べたい、複数の条件で並べたい、独自の順番にしたい場合は usort を使います。
Q. 降順にする usort の書き方は?
A. 比較の左右を入れ替えて fn($a, $b) => $b['price'] <=> $a['price'] とします。複数キーのときは、降順にしたい列だけ左右を入れ替えます。
Q. ランダムに並べ替えるには?
A. shuffle($a) を使います。キーは 0 から振り直されます。シード値を指定して再現したい場合は、PHP 8.2 以降の Random\Randomizer の shuffleArray が使えます(手元の 8.4.21 で、Mt19937 エンジンにシード 1 を渡して動作することを確かめました)。
Q. 並べ替えた後、連番のキーに戻したいときは?
A. array_values($a) で 0 からの連番に振り直せます。asort や natsort の結果を JSON の配列として出力したいときにも使えます。
まとめ
- 値で並べてキーを振り直すなら
sort、キーを維持するならasort、キーで並べるならksort。rが付くと降順、uが付くと比較関数を自分で書ける。 - ソート関数は配列を直接書き換え、戻り値は
true。結果は元の変数から読む。 - 多次元配列は
usortと<=>。複数キーは配列どうしの比較か?:でつなぐ。 array_multisortとarray_columnの組み合わせは高速。同順位の扱いがusortと異なる点を押さえておく。- 数字入りの文字列は
SORT_NATURAL、コードや ID はSORT_STRING、日本語のかなはCollator、漢字は読みがなの列で並べる。 - PHP 8.0 から安定ソートになり、同順位の要素は元の順番を保つ。
- PHP 8.0 で数値と文字列の比較が変わったので、型が混ざる配列はフラグか比較関数で比較方法を明示する。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「PHP配列ソート関数一覧 sort・usort・asort・ksortの違い」
株式会社RJCでは、PHPの配列操作やソートの使い分けを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。