🐘

PHPの配列のソートまとめ

に公開

はじめに

こんにちは、2018年新卒で入社し、PHPで求人系サービスの開発や社内向けツールの開発を行なっている @taku-0728 です。
今回は私が公式ドキュメントにてPHPで配列をソートするやり方を調べようと思ったところ、色々な関数があって戸惑ったので全部自分なりにまとめてみました。
長くなってしまうため、みたい情報だけピックアップしてみていただければと思います。

関数一覧

解説

sort

まず最初に紹介するのはsortです。
sortは配列の値を基準として昇順にソートしますが、連想配列であってもキーと値の組み合わせは維持されません。

$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
sort($fruitsLists);
var\_dump($fruitsLists);
array(4) {
  \[0\]=>
  string(5) "apple"
  \[1\]=>
  string(6) "banana"
  \[2\]=>
  string(5) "lemon"
  \[3\]=>
  string(6) "orange"
}

また、第2引数で比較条件を指定することもできます。
第2引数に指定可能な値は下記です。

  • SORT_REGULAR
    • デフォルトです。第2引数を省略した場合これが使われます。文字列の数値への変換が勝手に行われるため意図しないソート結果になることがあります。
    • 例えば下記の例だと同じ要素をソートしているにも関わらず結果が異なってしまいます。なんでこのような結果になるかは参考記事にも記載していますがこちらの記事がわかりやすいです。
      デフォルトですが極力使わずに、後述するSORT_NUMERICまたはSORT_STRINGのどちらかを使った方がいいと思います。
$array1=array("9", "1e1", "1f1");
sort($array1);
var\_dump($array1);
$array2=array("1e1", "1f1", "9");
sort($array2);
var\_dump($array2);
array(3) {
  \[0\]=>
  string(1) "9"
  \[1\]=>
  string(3) "1e1"
  \[2\]=>
  string(3) "1f1"
}
array(3) {
  \[0\]=>
  string(3) "1e1"
  \[1\]=>
  string(3) "1f1"
  \[2\]=>
  string(1) "9"
}
  • SORT_NUMERIC
    • 数字として項目を比較します。オプションを指定していない時と比較しても結果が異なっていないことが確認できます。
$array1=array("9", "1e1", "1f1");
sort($array1, SORT\_NUMERIC);
var\_dump($array1);
$array2=array("1e1", "1f1", "9");
sort($array2, SORT\_NUMERIC);
var\_dump($array2);
array(3) {
  \[0\]=>
  string(3) "1f1"
  \[1\]=>
  string(1) "9"
  \[2\]=>
  string(3) "1e1"
}
array(3) {
  \[0\]=>
  string(3) "1f1"
  \[1\]=>
  string(1) "9"
  \[2\]=>
  string(3) "1e1"
}
  • SORT_STRING
    • 文字列として項目を比較します。こちらもオプションを指定していない時と比較しても結果が異なっていないことが確認できます。
$array1=array("9", "1e1", "1f1");
sort($array1, SORT\_STRING);
var\_dump($array1);
$array2=array("1e1", "1f1", "9");
sort($array2, SORT\_STRING);
var\_dump($array2);
array(3) {
  \[0\]=>
  string(3) "1e1"
  \[1\]=>
  string(3) "1f1"
  \[2\]=>
  string(1) "9"
}
array(3) {
  \[0\]=>
  string(3) "1e1"
  \[1\]=>
  string(3) "1f1"
  \[2\]=>
  string(1) "9"
}
  • SORT_LOCALE_STRING
    • 現在のロケールに基づいて比較します。setlocale()でロケールを指定します。
// ロケールをオランダ語に設定
setlocale(LC\_ALL, 'nl\_NL');
// オランダ語が入った配列をソート
sort($netherLandsArray, SORT\_LOCALE\_STRING);

  • SORT_NATURAL
    • 項目の比較を文字列として行い、 後述のnatsort() と同様の「自然順」で比較します。
$array1 =  array("img12.png", "img10.png", "img2.png", "img1.png");
$array2 = $array1;
sort($array1);
var\_dump('asortの実行結果');
var\_dump($array1);
sort($array2, SORT\_NATURAL);
var\_dump('natsortの実行結果');
var\_dump($array2);
string(19) "sortの実行結果"
array(4) {
  \[0\]=>
  string(8) "img1.png"
  \[1\]=>
  string(9) "img10.png"
  \[2\]=>
  string(9) "img12.png"
  \[3\]=>
  string(8) "img2.png"
}
string(27) "SORT\_NATURALの実行結果"
array(4) {
  \[0\]=>
  string(8) "img1.png"
  \[1\]=>
  string(8) "img2.png"
  \[2\]=>
  string(9) "img10.png"
  \[3\]=>
  string(9) "img12.png"
}
  • SORT_FLAG_CASE
    • 文字列の比較で大文字小文字を区別しないようにします。SORT_STRINGやSORT_NATURALとOR条件(|)で組み合わせて使います。
$array1=array("aaa", "bbb", "AAA", "BBB");
sort($array1);
var\_dump('sortの実行結果');
var\_dump($array1);
$array2=array("aaa", "bbb", "AAA", "BBB");
sort($array2, SORT\_FLAG\_CASE|SORT\_STRING);
var\_dump('SORT\_FLAG\_CASE|SORT\_STRINGの実行結果');
var\_dump($array2);
string(19) "sortの実行結果"
array(4) {
  \[0\]=>
  string(3) "AAA"
  \[1\]=>
  string(3) "BBB"
  \[2\]=>
  string(3) "aaa"
  \[3\]=>
  string(3) "bbb"
}
string(41) "SORT\_FLAG\_CASE|SORT\_STRINGの実行結果"
array(4) {
  \[0\]=>
  string(3) "aaa"
  \[1\]=>
  string(3) "AAA"
  \[2\]=>
  string(3) "bbb"
  \[3\]=>
  string(3) "BBB"
}

rsort

sortの逆で、値を基準として降順にソートします。
キーと値の組み合わせが維持されない点と、第2引数でオプションが指定できる点も同様です。

$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
rsort($fruitsLists);
var\_dump($fruitsLists);
array(4) {
  \[0\]=>
  string(6) "orange"
  \[1\]=>
  string(5) "lemon"
  \[2\]=>
  string(6) "banana"
  \[3\]=>
  string(5) "apple"
}

asort

次に紹介するのはasortです。
asortは配列の値を基準として昇順にソートします。
sortと同様に第2引数でオプションを指定することもできます。
sortとの違いはキーと値の組み合わせは維持される点です。

$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
asort($fruitsLists);
var\_dump($fruitsLists);
array(4) {
  \["c"\]=>
  string(5) "apple"
  \["b"\]=>
  string(6) "banana"
  \["d"\]=>
  string(5) "lemon"
  \["a"\]=>
  string(6) "orange"
}

arsort

arsortはasortの逆で値を基準として降順にソートします。

$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
arsort($fruitsLists);
var\_dump($fruitsLists);
array(4) {
  \["a"\]=>
  string(6) "orange"
  \["d"\]=>
  string(5) "lemon"
  \["b"\]=>
  string(6) "banana"
  \["c"\]=>
  string(5) "apple"
}

ksort

ksortは配列のキーを基準として昇順にソートします。
asortが配列の値を基準としていたのに対し、こちらはキーを基準としています。
sortと同様に第2引数でオプションを指定することもできます。

$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
ksort($fruitsLists);
var\_dump($fruitsLists);
array(4) {
  \["a"\]=>
  string(6) "orange"
  \["b"\]=>
  string(6) "banana"
  \["c"\]=>
  string(5) "apple"
  \["d"\]=>
  string(5) "lemon"
}

krsort

krsortはksortの逆で配列のキーを基準として降順にソートします。

$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
krsort($fruitsLists);
var\_dump($fruitsLists);
array(4) {
  \["d"\]=>
  string(5) "lemon"
  \["c"\]=>
  string(5) "apple"
  \["b"\]=>
  string(6) "banana"
  \["a"\]=>
  string(6) "orange"
}

usort

usortはユーザー定義の比較関数により配列をその値でソートします。
つまり、コールバック関数を使って自分が指定した順番でソートできるということです。

function sortStrlen($a, $b) {
    // 同じ長さの場合には、順序を変えない
    if (strlen($a) === strlen($b)) {
        return 0;
    }
    // $aの方が短い場合には、$aの順番を$bより繰り下げる
    // $aの方が長い場合には、$aの順番を$bより繰り上げる
    return (strlen($a) < strlen($b)) ? -1 : 1;
};
$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
usort($fruitsLists, 'sortStrlen');
var\_dump($fruitsLists);
array(4) {
  \[0\]=>
  string(5) "lemon"
  \[1\]=>
  string(5) "apple"
  \[2\]=>
  string(6) "orange"
  \[3\]=>
  string(6) "banana"
}

uasort

uasortはusortと似ていますが、キーと値の組み合わせを保持する点に違いがあります。

function sortStrlen($a, $b) {
    // 同じ長さの場合には、順序を変えない
    if (strlen($a) === strlen($b)) {
        return 0;
    }
    // $aの方が短い場合には、$aの順番を$bより繰り下げる
    // $aの方が長い場合には、$aの順番を$bより繰り上げる
    return (strlen($a) < strlen($b)) ? -1 : 1;
};
$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
uasort($fruitsLists, 'sortStrlen');
var\_dump($fruitsLists);
array(4) {
  \["d"\]=>
  string(5) "lemon"
  \["c"\]=>
  string(5) "apple"
  \["a"\]=>
  string(6) "orange"
  \["b"\]=>
  string(6) "banana"
}

uksort

usortが配列の値を使って項目の比較を行なっていたのに対し、uksortは配列のキーを使って項目の比較を行います。

function sortStrlen($a, $b) {
    // 同じ長さの場合には、順序を変えない
    if (strlen($a) === strlen($b)) {
        return 0;
    }
    // $aの方が短い場合には、$aの順番を$bより繰り下げる
    // $aの方が長い場合には、$aの順番を$bより繰り上げる
    return (strlen($a) < strlen($b)) ? -1 : 1;
};
$fruitsLists = \[\];
$fruitsLists = \["aa" => "lemon", "aaa" => "orange", "a" => "banana", "aaaa" => "apple"\];
uksort($fruitsLists, 'sortStrlen');
var\_dump($fruitsLists);
array(4) {
  \["a"\]=>
  string(6) "banana"
  \["aa"\]=>
  string(5) "lemon"
  \["aaa"\]=>
  string(6) "orange"
  \["aaaa"\]=>
  string(5) "apple"
}

natsort

natsortはSORT_NATURALオプションを使用したときと同じように「自然順」アルゴリズムでキーと値の組み合わせを保持したまま配列をソートします。
わかりやすいようにasortと実行結果を比較してみます。

$array1 =  array("img12.png", "img10.png", "img2.png", "img1.png");
$array2 = $array1;
asort($array1);
var\_dump('asortの実行結果');
var\_dump($array1);
natsort($array2);
var\_dump('natsortの実行結果');
var\_dump($array2);
string(20) "asortの実行結果"
array(4) {
  \[3\]=>
  string(8) "img1.png"
  \[1\]=>
  string(9) "img10.png"
  \[0\]=>
  string(9) "img12.png"
  \[2\]=>
  string(8) "img2.png"
}
string(22) "natsortの実行結果"
array(4) {
  \[3\]=>
  string(8) "img1.png"
  \[2\]=>
  string(8) "img2.png"
  \[1\]=>
  string(9) "img10.png"
  \[0\]=>
  string(9) "img12.png"
}

asortでソートすると、2よりも1の方が数字として若いため、2より10や12が先になります。
それに対してnatsortでソートすると自然な数字の順番になっています。

natcasesort

natcasesortはnatsortと似ていますが大文字小文字を区別しない点に違いがあります。

$array1 =  array('IMG0.png', 'img12.png', 'img10.png', 'img2.png', 'img1.png', 'IMG3.png');
$array2 = $array1;
asort($array1);
var\_dump('asortの実行結果');
var\_dump($array1);
natcasesort($array2);
var\_dump('natcasesortの実行結果');
var\_dump($array2);
string(20) "asortの実行結果"
array(6) {
  \[0\]=>
  string(8) "IMG0.png"
  \[5\]=>
  string(8) "IMG3.png"
  \[4\]=>
  string(8) "img1.png"
  \[2\]=>
  string(9) "img10.png"
  \[1\]=>
  string(9) "img12.png"
  \[3\]=>
  string(8) "img2.png"
}
string(26) "natcasesortの実行結果"
array(6) {
  \[0\]=>
  string(8) "IMG0.png"
  \[4\]=>
  string(8) "img1.png"
  \[3\]=>
  string(8) "img2.png"
  \[5\]=>
  string(8) "IMG3.png"
  \[2\]=>
  string(9) "img10.png"
  \[1\]=>
  string(9) "img12.png"
}

array_multisort

array_multisortは主に多次元配列や複数の配列を一度にソートしたいときに使われます。
下記の例で果物の配列を名前の昇順かつ、価格の昇順になるようにソートしてみます。

$fluitsLists = \[
        \['name' =>'lemon','price' =>200\],
        \['name' =>'orange','price' =>100\],
        \['name' =>'banana','price' =>200\],
        \['name' =>'apple','price' =>300\],
    \];
// ソートの基準となる「name」と「price」を配列に入れる
foreach( $fluitsLists as $fluits) {
    $nameLists\[\] = $fluits\['name'\];
    $priceLists\[\] = $fluits\['price'\];
}
// ソート前の配列を出力
var\_dump('array\_multisortの実行前');
var\_dump($fluitsLists);
// ソート実行
array\_multisort($nameLists, SORT\_ASC, SORT\_STRING, $priceLists, SORT\_ASC, SORT\_NUMERIC, $fluitsLists);
// ソート後の配列を出力
var\_dump('array\_multisortの実行後');
var\_dump($fluitsLists);
string(27) "array\_multisortの実行前"
array(4) {
  \[0\]=>
  array(2) {
    \["name"\]=>
    string(5) "lemon"
    \["price"\]=>
    int(200)
  }
  \[1\]=>
  array(2) {
    \["name"\]=>
    string(6) "orange"
    \["price"\]=>
    int(100)
  }
  \[2\]=>
  array(2) {
    \["name"\]=>
    string(6) "banana"
    \["price"\]=>
    int(200)
  }
  \[3\]=>
  array(2) {
    \["name"\]=>
    string(5) "apple"
    \["price"\]=>
    int(300)
  }
}
string(27) "array\_multisortの実行後"
array(4) {
  \[0\]=>
  array(2) {
    \["name"\]=>
    string(5) "apple"
    \["price"\]=>
    int(300)
  }
  \[1\]=>
  array(2) {
    \["name"\]=>
    string(6) "banana"
    \["price"\]=>
    int(200)
  }
  \[2\]=>
  array(2) {
    \["name"\]=>
    string(5) "lemon"
    \["price"\]=>
    int(200)
  }
  \[3\]=>
  array(2) {
    \["name"\]=>
    string(6) "orange"
    \["price"\]=>
    int(100)
  }
}

結果を見ると名前の昇順かつ、価格の昇順になっていることがわかると思います。

shuffle

最後にソートとは少し違いますが、shuffleも紹介しておきます。
名前の通り、配列の順番をランダムにします。
この時キーと値の組み合わせが維持されない点に注意が必要です。

$fruitsLists = \[\];
$fruitsLists = \["d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple"\];
shuffle($fruitsLists);
var\_dump($fruitsLists);
array(4) {
  \[0\]=>
  string(6) "orange"
  \[1\]=>
  string(5) "apple"
  \[2\]=>
  string(6) "banana"
  \[3\]=>
  string(5) "lemon"
}

何度か実行したらわかりますが、実行するたびに結果が変わります。

まとめ

PHPで配列をソートするやり方について解説しました。
最近では並び替えなどはRDBで行うのが一般的であり、PHPで配列の並び替えを行う機会など多くはないかもしれませんが、いざという時のために知っておくと便利かなと思います。
最後までお付き合いいただきありがとうございました。

参考

配列のソート
【 php 】usort関数の使い方
多次元配列のソート:array_multisort関数
PHPのsort関数は相当おかしい

dipテックブログ

Discussion