countBy — 値ごとの件数を集計する

  • カテゴリ: collection
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN: Illuminate\Support\Collection::countBy
  • 関連: count / groupBy / mapToGroups / sum / collect
  • 変更履歴: 目立った仕様変更なし(初期から存在)

要点(TL;DR)

  • コレクション内の要素を「値ごとの件数」に集計するメソッド
  • collect($items)->countBy() で「値 → 出現回数」のコレクションを返す
  • :戻り値もコレクション/LazyCollection では全件走査/groupBy と用途が違う

概要

countBy は、コレクション内にある値の出現回数を「カテゴリ別の件数」として集計するメソッドです。
アクセスログからステータスコードごとの件数、ユーザー一覧から都道府県別の人数などを集計するのに便利です。
groupBy が「グループごとの配列」を返すのに対して、countBy は「グループごとの件数」を直接返します。

構文 / シグネチャ

public function countBy($callback = null): static

引数

引数必須既定値説明
$callback`callablestringnull`いいえ

callable のシグネチャ(典型例):

function ($value, $key): mixed

戻り値

  • Illuminate\Support\Collectionstatic
    • キー:集計対象の値(またはコールバックの戻り値)
    • 値:各キーに該当する要素数(int

例外 / 副作用

  • 直接的な例外はなし
  • LazyCollection に対して呼ぶと、全件イテレーションが走る(ストリーム処理では性能に注意)

使用例

最小例(値そのままを集計)

<?php

use Illuminate\Support\Collection;

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

$result = $numbers->countBy();

dump($result->all());
// [
//     1 => 1,
//     2 => 2,
//     3 => 3,
// ]

実務例1:ユーザー一覧から都道府県別人数を集計

<?php

use App\Models\User;

$users = User::all();

// 都道府県別のユーザー数
$prefCounts = $users->countBy(function ($user) {
    // null の場合は '不明' として集計
    return $user->prefecture ?? '不明';
});

// 例: ['東京' => 120, '大阪' => 80, '不明' => 5]
foreach ($prefCounts as $pref => $count) {
    echo "{$pref}: {$count}人" . PHP_EOL;
}

実務例2:ログ配列からステータスコード別の件数

<?php

$logs = collect([
    ['status' => 200],
    ['status' => 200],
    ['status' => 404],
    ['status' => 500],
    ['status' => 500],
    ['status' => 500],
]);

$statusCounts = $logs->countBy('status');

dump($statusCounts->toArray());
// [
//     200 => 2,
//     404 => 1,
//     500 => 3,
// ]

実務例3:時刻帯ごとのアクセス数を集計

<?php

use Carbon\Carbon;

$accessLogs = collect([
    ['accessed_at' => '2025-11-23 09:12:00'],
    ['accessed_at' => '2025-11-23 09:35:00'],
    ['accessed_at' => '2025-11-23 10:01:00'],
]);

$hourlyCounts = $accessLogs->countBy(function ($log) {
    $dt = Carbon::parse($log['accessed_at']);
    // 「09時」「10時」のような文字列で集計
    return $dt->format('H時');
});

dump($hourlyCounts->toArray());
// ['09時' => 2, '10時' => 1]

よくある落とし穴・注意

  • 戻り値も Collection
    • countBy() の結果に対してさらに ->sortDesc() などチェーンできるが、単純な件数合計が欲しいだけなら ->sum()->count() との混同に注意。
  • キーが string にキャストされることがある
    • true / false / null などをそのまま集計すると、1 / "" などにまとまるケースがあるため、必要ならコールバックで明示的にラベル化する。
  • LazyCollection は全件走査
    • 大量データを Eloquent でストリーミングしている場合、countBy() した時点で全件メモリに展開されるので注意。
    • 件数を SQL で出せるなら、DB の GROUP BY + COUNT(*) のほうが高速。

代替・関連APIとの比較

メソッド目的・特徴
count()コレクション全体の件数を 1 つの数値で取得
countBy()値ごとの件数を「値 → 件数」のマップで取得
groupBy()値ごとに要素を配列にグルーピング(件数は自分で ->map->count() などが必要)
sum()数値列の合計を取得(件数ではなく合計値)

選び方の目安

  • 「全体で何件あるか」→ count
  • 「都道府県ごとの人数」「ステータスコードごとの件数」→ countBy
  • 「グループごとにさらに別の集計・処理をしたい」→ groupBy + map など

チェーン可否・破壊性・計算量

  • チェーン可否: 可能(戻り値も Collection)
  • 破壊的/非破壊: 非破壊(元のコレクションは変更されない)
  • LazyCollection 対応: 対応するが全件走査になる
  • 計算量: おおよそ O(n)(要素数 n に比例して 1 回ずつ見る)

簡単な入出力イメージ:

collect(['a', 'b', 'a'])->countBy()->toArray();
// 入力: ['a', 'b', 'a']
// 出力: ['a' => 2, 'b' => 1]

テスト例(Pest)

<?php

use Illuminate\Support\Collection;

it('counts items by value', function () {
    $c = collect(['ok', 'ng', 'ok', 'ok']);

    $result = $c->countBy();

    expect($result->get('ok'))->toBe(3)
        ->and($result->get('ng'))->toBe(1);
});

it('counts items by callback key', function () {
    $c = collect([1, 2, 3, 4, 5]);

    // 偶数・奇数ごとに件数集計
    $result = $c->countBy(fn ($n) => $n % 2 === 0 ? 'even' : 'odd');

    expect($result->get('even'))->toBe(2)
        ->and($result->get('odd'))->toBe(3);
});

トラブルシュート(エラー別)

症状 / エラー原因対処
想定と違うキーで集計されるnull / true / false などがそのままキーになっているコールバックで '不明''yes'/'no' など明示的な文字列キーに変換する
メモリ使用量が急増するLazyCollection に対して大量データを countBy() しているDB 側 GROUP BY で集計するか、件数が必要な範囲だけに対象を絞る
件数だけ欲しいのに扱いが複雑countBy の結果が Collection で、その後の処理が複雑化しているgroupBy()->map->count() との比較を行い、必要に応じてロジックを整理

参考リンク

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする