【PHP】多次元配列を並び替える方法

データベースから取得したデータを並べ替えたいときは、SQL中で``ORDER BY``が使われます。

SQLやORマッパーで処理が完結すれば良いのですが、取得したデータに対して何らかの操作をし、その操作結果を元に、配列として並べ替えたい場合もあるかもしれません。（しかも多次元配列・・・）

なので、多次元配列を並べ替える方法をいくつか書き留めておきます。

# テスト用配列

```php
$clothes = array(
    array(
        'type' => 'male',
        'size' => 'S',
        'release_date' => '2019-04-10'
    ),
    array(
        'type' => 'female',
        'size' => 'M',
        'release_date' => '2019-02-15'
    ),
    array(
        'type' => 'child',
        'size' => 'S',
        'release_date' => '2019-01-05'
    ),
    array(
        'type' => 'female',
        'size' => 'M',
        'release_date' => '2019-05-20'
    ),
    array(
        'type' => 'male',
        'size' => 'L',
        'release_date' => '2019-03-30'
    )
);

var_dump($clothes);

// 出力結果
// array(5) {
//   [0]=>
//   array(3) {
//     ["type"]=>
//     string(4) "male"
//     ["size"]=>
//     string(1) "S"
//     ["release_date"]=>
//     string(10) "2019-04-10"
//   }
//   [1]=>
//   array(3) {
//     ["type"]=>
//     string(6) "female"
//     ["size"]=>
//     string(1) "M"
//     ["release_date"]=>
//     string(10) "2019-02-15"
//   }
//   [2]=>
//   array(3) {
//     ["type"]=>
//     string(5) "child"
//     ["size"]=>
//     string(1) "S"
//     ["release_date"]=>
//     string(10) "2019-01-05"
//   }
//   [3]=>
//   array(3) {
//     ["type"]=>
//     string(6) "female"
//     ["size"]=>
//     string(1) "M"
//     ["release_date"]=>
//     string(10) "2019-05-20"
//   }
//   [4]=>
//   array(3) {
//     ["type"]=>
//     string(4) "male"
//     ["size"]=>
//     string(1) "L"
//     ["release_date"]=>
//     string(10) "2019-03-30"
//   }
// }
```

# 1つのキー（カラム）を基準にソートする
多次元配列の並べ替えには、``array_multisort``を使います。

基準となるキーを指定し、そのキーに対応する値を格納する配列を作成します。
それを元にソートが行われます。

```php
<?php
// 指定したキーに対応する値を基準に、配列をソートする
function sortByKey($key_name, $sort_order, $array) {
    foreach ($array as $key => $value) {
        $standard_key_array[$key] = $value[$key_name];
    }

    array_multisort($standard_key_array, $sort_order, $array);
    
    return $array;
}

// release_dateを昇順ソートする
$sorted_array = sortByKey('release_date', SORT_ASC, $clothes);
var_dump($sorted_array);

// 出力結果
// array(5) {
//   [0]=>
//   array(3) {
//     ["type"]=>
//     string(5) "child"
//     ["size"]=>
//     string(1) "S"
//     ["release_date"]=>
//     string(10) "2019-01-05"
//   }
//   [1]=>
//   array(3) {
//     ["type"]=>
//     string(6) "female"
//     ["size"]=>
//     string(1) "M"
//     ["release_date"]=>
//     string(10) "2019-02-15"
//   }
//   [2]=>
//   array(3) {
//     ["type"]=>
//     string(4) "male"
//     ["size"]=>
//     string(1) "L"
//     ["release_date"]=>
//     string(10) "2019-03-30"
//   }
//   [3]=>
//   array(3) {
//     ["type"]=>
//     string(4) "male"
//     ["size"]=>
//     string(1) "S"
//     ["release_date"]=>
//     string(10) "2019-04-10"
//   }
//   [4]=>
//   array(3) {
//     ["type"]=>
//     string(6) "female"
//     ["size"]=>
//     string(1) "M"
//     ["release_date"]=>
//     string(10) "2019-05-20"
//   }
// }
```

# 複数のキー（カラム）を基準にソートする
``array_multisort``を使用する点、基準となるキーを指定し、そのキーに対応する値を格納する配列を作成する点は同じです。

SQLでは``ORDER BY type ASC, size ASC, release_date ASC``に当たる書き方です。
``array_multisort``の引数に、ソートの優先順に基準となる配列と並び順を指定します。

```php
<?php
// ソートの基準となるキーに対応する値の配列を作成
function createArrayForSort($key_name, $array) {
    foreach ($array as $key => $value) {
            $standard_key_array[$key] = $value[$key_name];
    }
    
    return $standard_key_array;
}

// 各キーを基準にソートできるように、対応する値の配列を作成
$type_array = createArrayForSort('type', $clothes);
$size_array = createArrayForSort('size', $clothes);
$release_date_array = createArrayForSort('release_date', $clothes);

// type, size, release_dateの優先順位で昇順ソートする
array_multisort($type_array, SORT_ASC, $size_array, SORT_ASC, $release_date_array, SORT_ASC, $clothes);
var_dump($clothes);

// 出力結果
// array(5) {
//   [0]=>
//   array(3) {
//     ["type"]=>
//     string(5) "child"
//     ["size"]=>
//     string(1) "S"
//     ["release_date"]=>
//     string(10) "2019-01-05"
//   }
//   [1]=>
//   array(3) {
//     ["type"]=>
//     string(6) "female"
//     ["size"]=>
//     string(1) "M"
//     ["release_date"]=>
//     string(10) "2019-02-15"
//   }
//   [2]=>
//   array(3) {
//     ["type"]=>
//     string(6) "female"
//     ["size"]=>
//     string(1) "M"
//     ["release_date"]=>
//     string(10) "2019-05-20"
//   }
//   [3]=>
//   array(3) {
//     ["type"]=>
//     string(4) "male"
//     ["size"]=>
//     string(1) "L"
//     ["release_date"]=>
//     string(10) "2019-03-30"
//   }
//   [4]=>
//   array(3) {
//     ["type"]=>
//     string(4) "male"
//     ["size"]=>
//     string(1) "S"
//     ["release_date"]=>
//     string(10) "2019-04-10"
//   }
// }
```

# ユーザー基準でソートする
``array_multisort``のソートのバリエーションは限られています。
配列をユーザー基準で並び替えたい場合、以下の方法が使えるかと思います。

あらかじめ、ソートの基準にするキーに対応する値をキーとした多次元配列を作成します。そこに配列の各要素を振り分けます。

ソート用のユーザー定義関数を作成するなど、他の方法もあるかもしれません。

```php
<?php
// あらかじめ表示順の基準とするキーに対応する値をキーとした配列を作成する
$array_by_size = array(
    'S' => array(),
    'M' => array(),
    'L' => array()
    );

// 値に応じて各要素を振り分ける
foreach($clothes as $key => $value) {
    $array_by_size[$value['size']][] = $value;
}

// 多次元配列で扱いづらいため、次元を１つ減らす
$sorted_array = call_user_func_array('array_merge', $array_by_size);

// array_mergeも使用できる
// $merge_array = array();
// foreach($array_by_size as $key => $value) {
//     foreach ($value as $data) {
//         $sorted_array[] = array_merge($merge_array, $data);
//     }
// }

var_dump($sorted_array);

// 出力結果
// array(5) {
//   [0]=>
//   array(3) {
//     ["type"]=>
//     string(4) "male"
//     ["size"]=>
//     string(1) "S"
//     ["release_date"]=>
//     string(10) "2019-04-10"
//   }
//   [1]=>
//   array(3) {
//     ["type"]=>
//     string(5) "child"
//     ["size"]=>
//     string(1) "S"
//     ["release_date"]=>
//     string(10) "2019-01-05"
//   }
//   [2]=>
//   array(3) {
//     ["type"]=>
//     string(6) "female"
//     ["size"]=>
//     string(1) "M"
//     ["release_date"]=>
//     string(10) "2019-02-15"
//   }
//   [3]=>
//   array(3) {
//     ["type"]=>
//     string(6) "female"
//     ["size"]=>
//     string(1) "M"
//     ["release_date"]=>
//     string(10) "2019-05-20"
//   }
//   [4]=>
//   array(3) {
//     ["type"]=>
//     string(4) "male"
//     ["size"]=>
//     string(1) "L"
//     ["release_date"]=>
//     string(10) "2019-03-30"
//   }
// }
```