1. ホーム
  2. PHP

【PHP】usort・uasort・uksort で配列を自由に並び替える方法|比較関数の書き方を解説

Share

PHP の sort()asort() は手軽ですが、「価格の安い順」「名前の五十音順」「連想配列の特定のキーで並べたい」といった独自の条件で並び替えたいときには物足りません。そんなときに使うのが usort() と、その仲間の uasort()uksort() です。この記事では、比較関数を自分で書いて配列を自由に並び替える方法を、よくあるユースケースとともに解説します。連想配列やオブジェクトの配列を思い通りに並べたい初心者〜中級者の方が対象です。

usort は「比較のルール」を自分で決められる

usort() は「user sort(ユーザー定義のソート)」の略で、2つの要素をどう比べるかを関数で渡して並び替えます。先頭の u が付くソート関数(usortuasortuksort)は、すべてこの「比較関数を自分で書く」タイプです。

比較関数は2つの引数 $a$b を受け取り、次のルールで整数を返します。この戻り値を見て、PHP がどちらを前に置くかを決めます。

比較関数の戻り値意味
負の数(例: -1$a$b より前に置く
0順序を変えない(同じ扱い)
正の数(例: 1$a$b より後ろに置く

基本の使い方(数値で並び替える)

まずは単純な数値の昇順で見てみます。数値の比較は $a - $b でも書けますが、現在は3つの値(負・0・正)を一度に返せる宇宙船演算子 <=>を使うのが定番です。$a <=> $b は、左が小さければ負、等しければ0、大きければ正を返します。

usort-basic.php
<?php
$scores = [80, 30, 95, 50];

// 昇順(小さい順)に並び替える
usort($scores, function ($a, $b) {
    return $a <=> $b;
});

print_r($scores);
// Array ( [0] => 30 [1] => 50 [2] => 80 [3] => 95 )

降順(大きい順)にしたいときは、$a$b を入れ替えて $b <=> $a と書くだけです。usort() は配列を直接書き換え、成功すると true を返します。元の配列を残したい場合は、渡す前にコピーしておきましょう。

なお usort() は処理後にキーを 0 から振り直す点に注意してください。元のキー(添字)を保ったまま並び替えたい場合は、後述の uasort() を使います。

連想配列を特定のキーで並び替える

実務でいちばん多いのが、「商品リストを価格順に」のように、連想配列の中の特定のキーで並び替えるケースです。比較関数の中で、それぞれの要素の比べたい値を取り出して <=> で比較します。

usort-by-key.php
<?php
$products = [
    ["name" => "りんご", "price" => 300],
    ["name" => "みかん", "price" => 120],
    ["name" => "ぶどう", "price" => 480],
];

// price の安い順に並び替える
usort($products, function ($a, $b) {
    return $a["price"] <=> $b["price"];
});

foreach ($products as $p) {
    echo "{$p['name']}: {$p['price']}円\n";
}
// みかん: 120円
// りんご: 300円
// ぶどう: 480円

PHP 7.4 以降ならアロー関数を使って、もっと短く書けます。1つの式だけで済む比較なら、こちらのほうが読みやすいでしょう。

usort-arrow.php
<?php
// アロー関数(fn)で同じ並び替えを短く書く
usort($products, fn($a, $b) => $a["price"] <=> $b["price"]);

2つ目の条件で並び替える(タイブレーク)

「価格が同じなら名前順にしたい」のように、第1条件が同点のときの並び順も決めたいことがあります。その場合は、最初の比較結果が 0 だったときに次の比較を行うように書きます。?:(省略形の三項演算子)を使うと、「左が 0 でなければ左、0 なら右」を簡潔に表現できます。

usort-multi.php
<?php
$users = [
    ["name" => "Bob",   "age" => 30],
    ["name" => "Alice", "age" => 30],
    ["name" => "Carol", "age" => 25],
];

// 年齢の昇順、同じ年齢なら名前のアルファベット順
usort($users, function ($a, $b) {
    return ($a["age"] <=> $b["age"])
        ?: ($a["name"] <=> $b["name"]);
});

foreach ($users as $u) {
    echo "{$u['name']} ({$u['age']})\n";
}
// Carol (25)
// Alice (30)
// Bob (30)

uasort と uksort の違い

usort() はキーを振り直してしまうため、連想配列の「キーと値の対応」を保ったまま値で並べたいときは uasort() を使います。また、値ではなくキーそのもので並び替えたいときは uksort() を使います。3つの違いを表にまとめます。

関数比較に使うものキーの扱い
usort()0 から振り直す
uasort()元のキーを保持する
uksort()キー元のキーを保持する
uasort-uksort.php
<?php
$stock = ["banana" => 12, "apple" => 30, "cherry" => 5];

// 値(在庫数)の昇順。キーと値の対応は保つ
uasort($stock, fn($a, $b) => $a <=> $b);
print_r($stock);
// Array ( [cherry] => 5 [banana] => 12 [apple] => 30 )

// キー(名前)のアルファベット順
uksort($stock, fn($a, $b) => $a <=> $b);
print_r($stock);
// Array ( [apple] => 30 [banana] => 12 [cherry] => 5 )

並び順がおかしくなるときの原因

比較関数が整数以外を返している

比較関数は負・0・正の整数を返す必要があります。$a > $b のように truefalse(真偽値)を返すと、PHP 8 では false が 0、true が 1 として扱われ、「小さい」ことを表現できないため正しく並びません。必ず <=> や引き算で整数を返しましょう。文字列の比較も <=> なら辞書順で正しく比較できます。

usort なのにキーを残したいと思っている

「並び替えたらキーが 0、1、2… に変わってしまった」というのは usort() の仕様どおりの動作です。連想配列のキーを保ちたいなら uasort() を、キー基準で並べたいなら uksort() を選びます。目的に合った関数を使えば、意図しないキーの振り直しを避けられます。

まとめ

usort() 系の関数を使えば、配列を自分のルールで自由に並び替えられます。要点を振り返ります。

  • 比較関数は $a$b を受け取り、負・0・正の整数を返す
  • 数値も文字列も $a <=> $b(宇宙船演算子)で比較するのが定番
  • 連想配列の特定キーで並べるなら、関数内でその値を取り出して比較する
  • usort はキーを振り直し、uasort は値で・uksort はキーで並べキーを保持する

まずは連想配列を価格順に並べる例から試し、タイブレークや uasort への置き換えに広げていくと、実務で扱う複雑な並び替えにも対応できるようになります。

参考ページ