intersect — コレクション同士の共通要素を取り出す

collection
  • カテゴリ: collection
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN / コマンド: Illuminate\Support\Collection::intersect
  • 関連: diff / intersectByKeys / unique / filter / whereIn
  • 変更履歴: Laravel 5系から存在。Laravel 12 でも基本仕様は同じ(Stillat)

要点(TL;DR)

  • 何に使うか:2つの配列/コレクションの「共通して含まれる値」だけを取り出す。
  • 最低限の使い方$result = collect([1, 2, 3])->intersect([2, 3, 4]);
  • よくある罠
    • キーは元のコレクションのまま 保持される(0,1,2…に振り直されない)
    • 「値」で比較するメソッドであり、「キー」は無視される
    • 巨大なデータで多用するとメモリ・CPUを食う(DBクエリで絞れるなら whereIn を優先)(Laravel)

概要

intersect は、コレクションと別の配列/コレクションの**積集合(共通部分)**を返すメソッドです。
Eloquent コレクションに対しても同じように使え、特定の ID 群や別クエリ結果との共通レコードだけを取り出すときに便利です。(Laravel)
計算は PHP の array_intersect と同様に行われ、新しいコレクションインスタンスとして結果が返されます。(Stillat)


構文 / シグネチャ

use Illuminate\Support\Collection;

/**
 * @param  \Illuminate\Support\Collection|array  $items
 * @return \Illuminate\Support\Collection
 */
public function intersect($items);

引数

引数必須既定値説明
itemsarray | Illuminate\Support\Collectionなし共通部分を取りたい相手側の配列/コレクション

戻り値

  • : Illuminate\Support\Collection
    • 元のコレクションと items 両方に含まれる値だけを持つ新しいコレクション
    • キーは「元のコレクション側」のキーが保持される(Stillat)

例外 / 副作用

  • 例外
    • items に配列でもコレクションでもない値を渡すと、PHP の型エラー(TypeError)になる可能性あり。
  • 副作用
    • 元のコレクションは変更されない(コレクションは基本的に不変)(Laravel)

使用例

最小例

use Illuminate\Support\Collection;

$collection = collect(['one', 'two', 'three', 'four', 'five']);

$result = $collection->intersect(['two', 'five', 'six']);

// $result は以下のようなコレクション
// collect([
//     1 => 'two',
//     4 => 'five',
// ]);
  • twofive が両方に含まれているため残る
  • キー 14元のコレクションのキー がそのまま残る(itsolutionstuff.com)

実務例:Eloquent コレクションで ID リストと突き合わせる

use App\Models\User;

// なんらかの条件で取得したユーザー一覧
$users = User::where('active', true)->get();

// 通知対象として許可されたユーザーID
$allowedUserIds = [1, 5, 8, 13];

// 「アクティブユーザー」かつ「許可リストにも含まれる」ユーザーだけに絞り込む
$targetUsers = $users->intersect(
    User::whereIn('id', $allowedUserIds)->get()
);

// $targetUsers は Eloquent\Collection のまま
foreach ($targetUsers as $user) {
    // 通知処理など
}
  • intersect に渡す側も Eloquent コレクションなので、モデルインスタンス同士の共通部分が取れる(Laravel)

実務例:タグIDの共通部分で記事を絞る(IDのコレクション同士)

use App\Models\Post;

// 記事A・記事Bに紐づくタグID一覧を取得
$postA = Post::findOrFail(10);
$postB = Post::findOrFail(20);

$tagIdsA = $postA->tags->pluck('id'); // コレクション
$tagIdsB = $postB->tags->pluck('id'); // コレクション

// 共通タグIDだけ取り出す
$commonTagIds = $tagIdsA->intersect($tagIdsB)->values();

// 共通タグを持つ他の記事を探す
$relatedPosts = Post::whereHas('tags', function ($q) use ($commonTagIds) {
    $q->whereIn('tags.id', $commonTagIds);
})->get();
  • values() でキーを振り直しておくと、そのまま whereIn に渡しやすい

よくある落とし穴・注意

  • キーが保持される
    • 0 からの連番にしたい場合は ->values() を追加する。
  • 「値」だけで比較される
    • キーは比較に使われない。キーでの共通部分を取りたい場合は intersectByKeys を使う。(itsolutionstuff.com)
  • ゆるい比較であることに注意
    • 内部的には PHP の array_intersect 相当の処理で、'1'1 は同じとみなされる挙動になる。
    • 型まで区別したい場合は、あらかじめ型を揃えるか、独自のフィルタロジック(filter + in_array(..., true))を実装する。
  • 巨大コレクションには不向き
    • 何万件ものモデルコレクション同士を intersect するより、DB レベルで whereIn や JOIN を使って絞る方が性能面で有利。

代替・関連APIとの比較

  • diff($items)
    • intersect の逆で、「相手側に存在しない値」を返す。除外フィルターに向いている。(Laravel)
  • intersectByKeys($items)
    • 「キー」で積集合を取る。連想配列的なデータ(設定配列など)でキー単位の共通部を取りたいときはこちら。(itsolutionstuff.com)
  • unique()
    • 片側のコレクション内で重複を削除する。2つの集合間の比較ではなく、単一集合の整理に使う。(Laravel)
  • Eloquent クエリビルダの whereIn()
    • DBクエリ時点での絞り込み。大量データの場合はこちらを優先し、intersect は「メモリ上の小さなセットの整形」に限定すると安全。(Laravel)

選定基準としては:

  • DBから取る前に絞れるか? → 可能なら whereIn などクエリで対応
  • すでに2つのコレクションが手元にあるか? → 値ベースなら intersect、キーなら intersectByKeys
  • 除外したいか?diff

テスト例(Pest)

use Illuminate\Support\Collection;

it('returns intersection of two collections', function () {
    $a = collect([10, 20, 30, 40]);
    $b = collect([20, 40, 50]);

    $result = $a->intersect($b);

    expect($result->all())->toBe([
        1 => 20,
        3 => 40,
    ]);
});

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

症状/エラー原因対処
結果が常に空コレクションになる片方の集合に含まれる値の型や値が微妙に違っている比較対象の配列・コレクションの中身と型を確認し、必要に応じてキャスト(map(fn ($v) => (int)$v)など)する
期待と違うキー(0,1,2…)にならないintersect は元のコレクションのキーを保持する->values() でキーを振り直す
implodejson_encode すると想定外の順序になるキーが飛び飛びのままだと、順序を前提にした処理が崩れるsort()values() で順序・キーを調整した上で後続処理を行う
大量データで処理が遅い・メモリを多く消費している巨大なコレクション同士をメモリ上で比較している事前に DB クエリで集約・絞り込みを行い、intersect は小さい集合に限定する

参考リンク

レン (Wren)

こんにちは。レンです。

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

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

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

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

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

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