PHP
Ginq

Ginq でオブジェクトをグループ分けする

More than 3 years have passed since last update.

GinqLINQ の PHP 実装の一つ。とてもよい。
Ginq に限らず LINQ 系全般に通じる話です。

PHP で配列内のオブジェクトを条件によってグループ分けする、ということをたまにやりたい場面があります。Ginq では次のように書くことができます。

// 例えばこんなクラスのオブジェクト配列があるとする
class EventSlate {
    /** @type string */
    public $date;
    /** @type string */
    public $title;

    public function __construct($date, $title)
    {
        $this->date = $date;
        $this->title = $title;
    }
}

$events = [
    new EventSlate('2014/10/15', '寿司駆動ハンズオン'),
    new EventSlate('2014/10/15', 'PHPもくもく会'),
    new EventSlate('2014/10/31', 'ハロウィンIT勉強会'),
    new EventSlate('2014/10/31', 'git push -f'),
    new EventSlate('2014/10/31', '仮装サーバ構築勉強会')
];

// ↑ を日付ごとにまとめてキーに日付を設定するには ↓ のようにする

$events_by_date = Ginq::from($events)
    ->groupBy(function(EventSlate $es) {
        return $es->date;
    })
    ->map(function(GroupingGinq $g) {
        return $g->toList();
    })
    ->toArray();

print_r($events_by_date);

出力は以下のようになります。

Array
(
    [2014/10/15] => Array
        (
            [0] => EventSlate Object
                (
                    [date] => 2014/10/15
                    [title] => 寿司駆動ハンズオン
                )

            [1] => EventSlate Object
                (
                    [date] => 2014/10/15
                    [title] => PHPもくもく会
                )

        )

    [2014/10/31] => Array
        (
            [0] => EventSlate Object
                (
                    [date] => 2014/10/31
                    [title] => ハロウィンIT勉強会
                )

            [1] => EventSlate Object
                (
                    [date] => 2014/10/31
                    [title] => git push -f
                )

            [2] => EventSlate Object
                (
                    [date] => 2014/10/31
                    [title] => 仮装サーバ構築勉強会
                )

        )

)

「オブジェクトをグループ化」というと groupBy が思い浮かびますが、検索しても「グループ化して集計」とか「グループ化して平均値を計算」とかばかりで、オブジェクトをそのままグループ分けして連想配列にする方法は見つかりませんでした。

要するに、groupBy という機能自体は flatMap の逆で、複数の集合のシーケンスを作成するものなんですね。さらに groupBy は自動的にキーを設定してくれるみたいで、とても使い勝手がよいですね。