[PHP]uksortとは?配列のキーを独自ロジックで並び替える方法を徹底解説

PHP

はじめに

前回の記事では、値をユーザー定義の比較関数でソートしつつキーを保持する uasort() を解説しました。今回紹介する uksort() は、それとよく似ていますがソートの対象が「値」ではなく「キー」であるという点が異なります。

uksort() は、配列のキーを独自の比較関数で並び替えるための関数です。名前の “u” は “user-defined”(ユーザー定義)、”k” は “key”(キー)を意味します。文字列キーを数値的に比較したい、キーに含まれるバージョン番号順に並べたい、特定の優先順位リストに従ってキーを並べ替えたい、といった場面で活躍します。本記事では基本的な使い方から実践的な活用例まで詳しく解説します。


関数概要

項目内容
関数名uksort()
所属拡張コア関数(標準で常に利用可能)
シグネチャuksort(array &$array, callable $callback): bool
引数1$array — ソート対象の配列(参照渡し)
引数2$callback — 2つのキーを比較するコールバック関数
戻り値成功時に true
対応バージョンPHP 4以降
ソート対象配列のキー(値ではない)
類似関数uasort()(値をソート、キー保持)、ksort()(キーの標準比較)

ソートの流れ(イメージ図)

  ソート前の配列
  ['v10' => '安定版', 'v2' => '旧版', 'v1' => '最古版']
                  │
                  ▼
   uksort($array, function($a, $b) {
       return (int)substr($a, 1) <=> (int)substr($b, 1);
   })
                  │
   ┌──────────────┴──────────────────┐
   │ キー同士を比較関数で比較する          │
   │ (単純な文字列比較では "v10" < "v2" になってしまう) │
   │ 数値として比較することで正しい順序に    │
   └──────────────┬──────────────────┘
                  ▼
  ソート後の配列(キーの順序が変わり、値も一緒に移動する)
  ['v1' => '最古版', 'v2' => '旧版', 'v10' => '安定版']

ポイントは、"v2""v10" のような文字列キーを単純な文字列比較でソートすると "v10""v2" より前に来てしまう(辞書順では "1""2" より小さい)という問題です。uksort() を使えば、こうしたケースでも独自の比較ロジックによって意図した順序(数値としての大小関係)でソートできます。


実践サンプル7選

例1:基本的な使い方

<?php

class BasicUksortDemo
{
    public function sortByKey(array $data): array
    {
        // キー同士を比較する関数を指定する
        uksort($data, fn ($a, $b) => $a <=> $b);
        return $data;
    }
}

$demo = new BasicUksortDemo();
$data = ['banana' => 3, 'apple' => 1, 'cherry' => 2];
print_r($demo->sortByKey($data));
// ['apple' => 1, 'banana' => 3, 'cherry' => 2]  ← キーのアルファベット順

例2:バージョン番号を含むキーを正しい順序でソートする

<?php

class VersionKeySorter
{
    /**
     * "v1", "v2", "v10" のようなキーを
     * 文字列順ではなく数値として正しくソートする
     */
    public function sort(array $versions): array
    {
        uksort($versions, function (string $a, string $b) {
            $numA = (int) substr($a, 1);
            $numB = (int) substr($b, 1);
            return $numA <=> $numB;
        });

        return $versions;
    }
}

$sorter = new VersionKeySorter();
$versions = ['v10' => '安定版', 'v2' => '旧版', 'v1' => '最古版'];
print_r($sorter->sort($versions));
// ['v1' => '最古版', 'v2' => '旧版', 'v10' => '安定版']

例3:カスタム優先順位リストに基づいてキーを並び替える

<?php

class PriorityKeySorter
{
    /**
     * @var array<string, int> キー名 => 優先順位のマップ
     */
    private array $priorityMap;

    public function __construct(array $priorityOrder)
    {
        // 配列の並び順から優先順位のマップを生成しておく
        $this->priorityMap = array_flip($priorityOrder);
    }

    public function sort(array $data): array
    {
        uksort($data, function ($a, $b) {
            $priorityA = $this->priorityMap[$a] ?? PHP_INT_MAX;
            $priorityB = $this->priorityMap[$b] ?? PHP_INT_MAX;
            return $priorityA <=> $priorityB;
        });

        return $data;
    }
}

$sorter = new PriorityKeySorter(['name', 'email', 'phone', 'address']);
$formData = ['address' => '東京都', 'name' => '太郎', 'phone' => '090-xxxx', 'email' => 'a@example.com'];
print_r($sorter->sort($formData));
// 指定した優先順位(name, email, phone, address)通りに並び替わる

例4:大文字小文字を区別しないキーソート

<?php

class CaseInsensitiveKeySorter
{
    /**
     * キーの大文字小文字を無視してアルファベット順にソートする
     */
    public function sort(array $data): array
    {
        uksort($data, fn ($a, $b) => strcasecmp((string) $a, (string) $b));
        return $data;
    }
}

$sorter = new CaseInsensitiveKeySorter();
$data = ['Banana' => 1, 'apple' => 2, 'Cherry' => 3];
print_r($sorter->sort($data));
// ['apple' => 2, 'Banana' => 1, 'Cherry' => 3]

例5:日付形式のキーを時系列順にソートする

<?php

class DateKeySorter
{
    /**
     * "2026-08-05" のような日付文字列をキーに持つ配列を
     * 時系列順にソートする
     */
    public function sortChronologically(array $dailyLogs): array
    {
        uksort($dailyLogs, function (string $a, string $b) {
            $timeA = strtotime($a);
            $timeB = strtotime($b);
            return $timeA <=> $timeB;
        });

        return $dailyLogs;
    }
}

$sorter = new DateKeySorter();
$logs = [
    '2026-08-05' => '通常運用',
    '2026-07-30' => 'メンテナンス実施',
    '2026-08-01' => '障害対応',
];
print_r($sorter->sortChronologically($logs));

例6:多次元配列のキー(グループ名)を自然順ソートする

<?php

class NaturalKeySorter
{
    /**
     * strnatcmp()を利用して、
     * "item2" と "item10" のようなキーを自然な順序でソートする
     */
    public function sort(array $data): array
    {
        uksort($data, fn ($a, $b) => strnatcmp((string) $a, (string) $b));
        return $data;
    }
}

$sorter = new NaturalKeySorter();
$data = ['item10' => 'C', 'item2' => 'B', 'item1' => 'A'];
print_r($sorter->sort($data));
// ['item1' => 'A', 'item2' => 'B', 'item10' => 'C']  ← 自然な順序

例7:設定ファイルのセクションキーを重要度でグルーピングしながらソート

<?php

class ConfigSectionSorter
{
    private const IMPORTANCE = [
        'database' => 1,
        'cache'    => 2,
        'logging'  => 3,
    ];

    /**
     * 定義済みの重要度マップに存在するキーを優先し、
     * それ以外のキーはアルファベット順で後ろに並べる
     */
    public function sort(array $config): array
    {
        uksort($config, function ($a, $b) {
            $importanceA = self::IMPORTANCE[$a] ?? null;
            $importanceB = self::IMPORTANCE[$b] ?? null;

            if ($importanceA !== null && $importanceB !== null) {
                return $importanceA <=> $importanceB;
            }
            if ($importanceA !== null) {
                return -1;
            }
            if ($importanceB !== null) {
                return 1;
            }
            return strcmp((string) $a, (string) $b);
        });

        return $config;
    }
}

$sorter = new ConfigSectionSorter();
$config = ['mail' => [], 'cache' => [], 'database' => [], 'app' => []];
print_r($sorter->sort($config));
// ['database' => [], 'cache' => [], 'app' => [], 'mail' => []]

関連関数との比較

関数役割uksortとの違い
uksort()キーをユーザー定義の比較関数でソート本記事の対象。ソート対象は「キー」
uasort()値をユーザー定義の比較関数でソート(キー保持)ソート対象が「値」である点が異なる
usort()値をユーザー定義の比較関数でソートキーが保持されず連番に振り直される
ksort()キーの標準的な比較でソート独自の比較ロジックを指定できない点が異なる
krsort()キーの標準的な比較で降順ソートuksort()で降順にする場合は比較関数の引数順を入れ替える

よくある落とし穴(注意点)

  1. 比較関数はキーを受け取ることを忘れない uksort() のコールバックに渡されるのは配列の「値」ではなく「キー」です。uasort() と混同して値を前提とした比較ロジックを書いてしまうと、意図しない結果になります。
  2. キーの型が数値か文字列かを意識する PHPの配列キーは数値または文字列ですが、比較関数内で暗黙の型変換に依存すると予期しない挙動になることがあります。必要に応じて (int)(string) で明示的にキャストしましょう。
  3. 単純な文字列比較では数値を含むキーが期待通りにならない "v2""v10" の例のように、文字列としての辞書順比較では直感に反する結果になることがあります。数値部分を抽出して比較する、または strnatcmp() を使うことで解決できます(例2・例6を参照)。
  4. 元の値との対応関係は崩れない uksort() はキーの順序だけを並び替える関数であり、各キーに対応する値は移動先に一緒についていきます。値だけを個別に並び替えるわけではない点を理解しておきましょう。
  5. 重い比較処理はパフォーマンスに影響する uasort() と同様、比較関数内で複雑な処理を行うと要素数に応じて呼び出し回数が増加します。優先順位マップなど、事前に計算できるデータはループの外で用意しておくのが望ましいです(例3・例7を参照)。

まとめ

観点まとめ
何をする関数かユーザー定義の比較関数を使って配列の「キー」を並び替える
主な用途バージョン番号順のソート、優先順位に基づく並び替え、自然順ソートなど
ソート対象キー(値ではない)。値はキーに追従して移動する
類似関数との違いuasort()は値をソート、uksort()はキーをソートする
注意点コールバックに渡されるのはキーであること、数値を含む文字列キーの比較方法

uksort() は、配列のキーそのものに意味がある場合に非常に役立つ関数です。バージョン番号や日付、独自の優先順位リストなど、標準の ksort() では対応できない複雑な並び替えロジックが必要なときは、ぜひ uksort() の活用を検討してみてください。

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