Laravel Collection 並び替えやグループ化 sort/groupby/pluckなど

シェアしてね〜🤞

LaravelのCollectionとは

LaravelのCollectionは、PHPの配列をより便利に使うためのラッパークラスです。

前回の記事ではCollectionの基本、toArray、map、each、filter、whereメソッドをご紹介しました。

Collectionのメソッドはまだたくさんありますが、その知識を習得すればするほど、実務において非常に役立つと感じられるでしょう。

この記事では新たに、以下のメソッドを学んでいきましょう。

  • sort
  • sortBy
  • count
  • groupBy
  • pluck

sort

sortメソッドは、要素を並べ替えるために使います。

例えば、ばらばらの大きさで並んでいる数値の配列を、昇順(小さい順)に並べ替えるときに役立ちます。

前回の記事でお話ししたように、このメソッドも元のCollectionに変更を加えずに、新しいCollectionを返します。

$numbers = collect([3, 1, 5, 2, 4]);

$asc = $numbers->sort();

/*
$asc->toArray():
    [
        1 => 1,
        3 => 2,
        0 => 3,
        4 => 4,
        2 => 5,
    ]
*/

降順(大きい順)に並べ替えたいときはsortDescメソッドを使います。

$desc = $numbers->sortDesc();

/*
$desc->toArray():
    [
        2 => 5,
        4 => 4,
        0 => 3,
        3 => 2,
        1 => 1,
    ]
*/

注意していただきたいのは、確かに並べ替えられたものの、キーは元のままである点です。

連番の配列がほしいときはどうすればいいのでしょうか。

キーを連番にリセットするvaluesメソッド

順番は変わったのにキーが元のままということは、Collectionではよくあることです。

こういうときは、キーを連番にリセットするvaluesメソッドの出番です。

sortに続けて使ってみましょう。

$numbers = collect([3, 1, 5, 2, 4]);

$sorted = $numbers->sort()->values();

/*
$sorted->toArray():
    [
      0 => 1,
      1 => 2,
      2 => 3,
      3 => 4,
      4 => 5,
    ]
*/

sortにクロージャを渡す

sortで並べ変えることができるのは数値だけではありません。

sortは文字列も並べ替えてくれます。

$events = collect([
    '11/23 勤労感謝の日',
    '5/5 こどもの日',
    '1/1 元日',
    '11/3 文化の日',
]);

$sorted = $events->sort()->values();

/*
$sorted->toArray():
    [
        0 => "1/1 元日",
        1 => "11/23 勤労感謝の日",
        2 => "11/3 文化の日",
        3 => "5/5 こどもの日",
    ]
*/

並べ替えられましたが違和感があります。

機械的な文字の順番としてはこの並びが正しいのですが、文字列の先頭が日付であるという人間の意図が反映されていません。

こういうときはsortにクロージャを渡すことで、並び替えの条件を具体的に指定することができます。

// 例えば'1/1 元日'を'01/01 元日'に変換する
function padDate($str) {
    $exploded = explode(' ', $str);  // ['1/1', '元日']
    $name = $exploded[1];

    $exploded2 = explode('/', $exploded[0]);  // ['1', '1']
    $mon = Str::padLeft($exploded2[0], 2, '0');
    $day = Str::padLeft($exploded2[1], 2, '0');

    return "$mon/$day $name";
}

$sorted2 = $events->sort(function($a, $b) {
    return strcmp(padDate($a), padDate($b));
})->values();

/*
$sorted2->toArray():
    [
        0 => "1/1 元日",
        1 => "5/5 こどもの日",
        2 => "11/3 文化の日",
        3 => "11/23 勤労感謝の日",
    ]
*/

sortBy

key=>value形式のCollectionを昇順に並べ替えたいときは、sortByメソッドが便利です。

降順に並べ替えるsortByDescメソッドもあります。

$users = collect([
    ['name' => 'サザエ', 'gender' => 'female', 'age' => 24],
    ['name' => '波平', 'gender' => 'male', 'age' => 54],
    ['name' => 'フネ', 'gender' => 'female', 'age' => 50],
    ['name' => 'マスオ', 'gender' => 'male', 'age' => 28],
]);

$sorted = $users -> sortBy('age');

/* 
$sorted->toArray():
    [
        ['name' => 'サザエ', 'gender' => 'female', 'age' => 24],
        ['name' => 'マスオ', 'gender' => 'male', 'age' => 28],
        ['name' => 'フネ', 'gender' => 'female', 'age' => 50],
        ['name' => '波平', 'gender' => 'male', 'age' => 54],
     ]
*/

count

countメソッドは、Collection内の要素の数を返します。

$items = collect(['apple', 'banana', 'orange']);

$count = $items->count(); // $countには3が代入される

groupBy

groupByメソッドは、key=>value形式のCollectionの要素を指定したキーに基づいてグループ化します。

例えば、ユーザーを男女に分けたいときに便利です。

$users = collect([
    ['name' => 'サザエ', 'gender' => 'female', 'age' => 24],
    ['name' => '波平', 'gender' => 'male', 'age' => 54],
    ['name' => 'フネ', 'gender' => 'female', 'age' => 50],
    ['name' => 'マスオ', 'gender' => 'male', 'age' => 28],
]);

$grouped = $users->groupBy('gender');

/* 
$grouped->toArray():
    [
        'female'=> [
            ['name' => 'サザエ', 'gender' => 'female', 'age' => 24],
            ['name' => 'フネ', 'gender' => 'female', 'age' => 50],
        ],
        'male' => [
            ['name' => '波平', 'gender' => 'male', 'age' => 54],
            ['name' => 'マスオ', 'gender' => 'male', 'age' => 28],
        ]
    ]
*/

pluck

pluckメソッドも、key=>value形式のCollectionに対して使うメソッドで、特定のkeyを持つ値だけを抽出してCollectionを作ってくれます。

例えば、ユーザー情報が手元にあるけど、そこからユーザー名だけの配列を作りたいというときに便利です。

$users = collect([
    ['name' => 'サザエ', 'gender' => 'female', 'age' => 24],
    ['name' => '波平', 'gender' => 'male', 'age' => 54],
    ['name' => 'フネ', 'gender' => 'female', 'age' => 50],
    ['name' => 'マスオ', 'gender' => 'male', 'age' => 28],
]);

$names = $users->pluck('name');
/*
$names->toArray():
    ['サザエ', '波平', 'フネ', 'マスオ']
*/

組み合わせて使ってみよう

Collectionのメソッドは単発で使うだけでも、生の配列を処理するよりも簡潔に書けますが、組み合わせて使うとき、特にその簡潔さが際立ちます。

例えば、ユーザーの年齢の昇順の配列が欲しいとき、このように書くことができます。

$users
    ->pluck('age')
    ->sort()
    ->values()
    ->toArray();

/*
    [24, 28, 50, 54]
*/

次に、ユーザーを若い順に並び替え、男女別に分けてみましょう。

$names = $users
    ->sortBy('age')
    ->groupBy('gender')
    ->toArray();

/*
    [
        'female'=> [
            ['name' => 'サザエ', 'gender' => 'female', 'age' => 24],
            ['name' => 'フネ', 'gender' => 'female', 'age' => 50],
        ],
        'male' => [
            ['name' => 'マスオ', 'gender' => 'male', 'age' => 28],
            ['name' => '波平', 'gender' => 'male', 'age' => 54],
        ]
    ]
*/

いずれの場合も、生の配列でやろうと思うと、書くのも読むのも億劫なコードになってしまいます。

Collectionを上手に使うことで、きれいで保守性の高いコードを書くことを心がけましょう。

シェアしてね〜🤞