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をコピーしました