PHPのユーザー定義関数でソートする(usort, uasort, uksort)

PHP

今回は、PHPでユーザー定義関数でソートをする標準関数の挙動を確認していきます。
前回はsortasortksortなどのソート関数について見ていきました。

今回は下記のユーザー定義関数を使用してソートする標準関数を使ってみました。

・usort
・uasort
・uksort

ユーザー定義関数でのソートは、配列の内容を関数に定義した処理でソートします。
載せているサンプルコードはPHPのバージョン8で検証しています。

usort・uasort・uksortの比較表

公式ドキュメントからusort・uasort・uksortの箇所だけ抜き出して、表にしました。
公式ドキュメントはこちらです。

関数 ソートの基準 キーと値の相関関係 ソート順
usort 維持しない ユーザー定義
uasort 維持する ユーザー定義
uksort キー 維持する ユーザー定義

ユーザー定義のソート関数はuから始まっています。
それぞれの違いは、下記になります。

・ソートの基準を値にするかキーにするか
・キーと値の関係を維持するか

また、ソート順のところがユーザー定義になっています。
このユーザー定義は、ユーザーが関数で定義したソート順になります。

詳しくは次項以降で確認してきましょう。

usort関数を使ってソートする

usort関数は第1引数にソートしたい配列、第2引数にユーザー定義関数を渡してソートします。
ユーザー定義関数は、配列の値を比較する内容で処理を書きます。

下記のように処理を書いて並び替えることができます。

<?php

$fruits = [
    1 => 'orange',
    2 => 'grape',
    3 => 'apple',
    4 => 'peach',
    5 => 'banana',
];

function mySort($firstValue, $secondValue) {
    if ($firstValue === $secondValue) {
        return 0;
    }

    return ($firstValue < $secondValue) ? -1 : 1;
}

usort($fruits, 'mySort');
print_r($fruits);

$fruitsに入っている配列をusort関数で並び替えています。
並び替えに使っている関数が、第2引数に指定しているmySort関数です。

mySort関数の中で、渡された$firstValue$secondValueを比較します。
この2つの変数には、配列の値が入っています。

配列の値を比べて、同じだった場合は0を返しています。
$firstValue$secondValueより小さい場合には-1を返して、大きい場合には1返しています。

これでソートした結果は、下記になります。

Array
(
    [0] => apple
    [1] => banana
    [2] => grape
    [3] => orange
    [4] => peach
)

このように値を比較する関数を書くことで、配列のデータをソートします。

usort関数は、「値を基準」にソートして、「キーと値の関係を維持しない」ソートでした。
値がソートされて、キーが振り直されていることが確認できます。

ソート順がユーザー定義ということでした。
下記のように返しているため昇順になっています。

return ($firstValue < $secondValue) ? -1 : 1;

この比較箇所を逆にすると、降順になります。
下記のように比較箇所を反対にします。

return ($firstValue > $secondValue) ? -1 : 1;

そうすると、結果が下記のように、降順になります。

Array
(
    [0] => peach
    [1] => orange
    [2] => grape
    [3] => banana
    [4] => apple
)

uasort関数を使ってソートする

uasort関数もusort関数と同じように使用することが可能です。
こちらも、第1引数にソートしたい配列、第2引数にユーザー定義関数を渡してソートします。
違いは「キーと値の関係を維持する」というところです。

同じ配列を下記のように、uasort関数でソートしてみました。

<?php

$fruits = [
    1 => 'orange',
    2 => 'grape',
    3 => 'apple',
    4 => 'peach',
    5 => 'banana',
];

function mySort($firstValue, $secondValue) {
    if ($firstValue === $secondValue) {
        return 0;
    }

    return ($firstValue < $secondValue) ? -1 : 1;
}


uasort($fruits, 'mySort');
print_r($fruits);

上記のプログラムの出力結果は下記のようになります。
配列のキーが維持されたまま、下記のように値がソートされていることが確認できました。

Array
(
    [3] => apple
    [5] => banana
    [2] => grape
    [1] => orange
    [4] => peach
)

こちらも比較箇所を変えることで、降順にできます。
下記のように、比較箇所を変えてみます。

return ($firstValue > $secondValue) ? -1 : 1;

そうすると、結果としてこのように出力されます。
降順になって、キーが維持されていることが確認できました。

Array
(
    [4] => peach
    [1] => orange
    [2] => grape
    [5] => banana
    [3] => apple
)

uksort関数を使ってソートする

uksort関数もusort関数と同じように使用することが可能です。
こちらも、第1引数にソートしたい配列、第2引数にユーザー定義関数を渡してソートします。
usort関数との違いは「キーを基準にソートする」のと「キーと値の関係を維持する」という箇所です。

同じ配列を下記のように、uksort関数でソートしてみました。
そのままだと、並び順が変わらないので、配列のキーは変更しました。

<?php

$fruits = [
    3 => 'orange',
    5 => 'grape',
    1 => 'apple',
    4 => 'peach',
    2 => 'banana',
];

function mySort($firstValue, $secondValue) {
    if ($firstValue === $secondValue) {
        return 0;
    }

    return ($firstValue < $secondValue) ? -1 : 1;
}


uksort($fruits, 'mySort');
print_r($fruits);

出力される結果は、下記のようになります。

Array
(
    [1] => apple
    [2] => banana
    [3] => orange
    [4] => peach
    [5] => grape
)

キーを基準にして、昇順に並ぶことが確認できました。
キーと値の関係も維持されたまま、キーの昇順で並んでいます。

こちらも比較箇所を変えることで、降順にできます。
下記のように変更します。

return ($firstValue > $secondValue) ? -1 : 1;

そうすると、出力結果は下記のようにキーの降順で並ぶようになります。

Array
(
    [5] => grape
    [4] => peach
    [3] => orange
    [2] => banana
    [1] => apple
)

配列の複数項目でソートする

usortuasortuksortのそれぞれの違いの確認ができました。
ユーザー定義のソート関数ということで、複雑なソートを行うことも可能です。

配列の複数の値を元にソートしてみます。

<?php

$items = [
    [
        'group_id' => 1,
        'item_name' => 'apple',
        'price' => 120,
    ],
    [
        'group_id' => 2,
        'item_name' => 'banana',
        'price' => 130,
    ],
    [
        'group_id' => 1,
        'item_name' => 'grape',
        'price' => 140,
    ],
    [
        'group_id' => 2,
        'item_name' => 'orange',
        'price' => 150,
    ],
];

function mySort($firstValue, $secondValue) {
    if ($firstValue['group_id'] === $secondValue['group_id']) {
        if ($firstValue['price'] === $secondValue['price']) {
            return 0;
        }
        return ($firstValue['price'] > $secondValue['price']) ? -1 : 1;
    }
    return ($firstValue['group_id'] < $secondValue['group_id']) ? -1 : 1;
}

usort($items, 'mySort');
print_r($items);

$itemsを多次元配列にして、それぞれの配列にgroup_iditem_namepriceの項目を持っています。
これをusort関数を使用して、値を基準にソートします。

ソート順は、group_idの昇順でpriceの降順にします。
mySort関数の中を確認してもらうと、if文がネストしていますが、このようにすることで複数の項目でソートができます。

最初にgroup_idを比較して、昇順に並べています。
group_idが同じだった場合は、priceを参照して、降順にしています。
group_idからpriceのように、ネストが浅い箇所から、並び順の条件として効いてきます。

このプログラムの出力結果は下記のようになります。

Array
(
    [0] => Array
        (
            [group_id] => 1
            [item_name] => grape
            [price] => 140
        )

    [1] => Array
        (
            [group_id] => 1
            [item_name] => apple
            [price] => 120
        )

    [2] => Array
        (
            [group_id] => 2
            [item_name] => orange
            [price] => 150
        )

    [3] => Array
        (
            [group_id] => 2
            [item_name] => banana
            [price] => 130
        )

)

group_idが昇順になって、その後にpriceの降順になっているのが確認できます。

終わりに

今回はユーザー定義のソート関数で配列を並べる方法を確認していきました。
usortuasortuksortそれぞれ同じように使用できますが、結果は異なるので、挙動に注意して使用するようにしましょう。

最後に紹介したように、複数配列の項目の並び順で便利な関数です。
基本的にはデータベースのテーブルから値を取得するときにOrder句などを使って並べると思います。
データベースを使用できない場合や、配列項目を複数条件で並べたい時に役にたちそうですね。

コメント

タイトルとURLをコピーしました