union — 左優先のキー結合(上書きなし)

collection
  • カテゴリ: collection
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN / コマンド: Illuminate\Support\Collection::union
  • 関連: merge / concat / replace / intersectByKeys / unique
  • 変更履歴: —

要点(TL;DR)

  • 何に使うか:左(元)コレクションのキーを優先し、存在しないキーだけ右側から追加する。
  • 最低限の使い方$a->union($b)
  • よくある罠
    • 値の“集合(ユニーク)結合”ではない(キーで結合)
    • 数値キーは左が優先され、右の同一キーは無視される
    • 連番配列同士だと何も増えないことがある(例:[1,2][2,3][1,2]

概要

union は PHP の配列演算子 + と同等で、左側の既存キーを保ちつつ、右側にしかないキーを追加します。上書きは一切行いません。設定の“デフォルトを固定して一部だけ後から足す”といった用途に向きます。値ベースでユニークに結合したい場合は別手段(concat()->unique() など)を使います。

構文 / シグネチャ

/**
 * 左コレクションのキーを優先し、存在しないキーだけ $items から追加する
 *
 * @param  iterable|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable|array $items
 * @return \Illuminate\Support\Collection  // 新しいインスタンス(非破壊)
 */
public function union($items);
  • 引数(表)
引数必須既定値説明
$itemsiterable | Arrayable | JsonSerializable | arrayはい右側に結合する要素群。キーの衝突時は無視される(左優先)。
  • 戻り値Collection(新しいコレクション。元は変更しない)
  • 例外/副作用:なし(ただし大きな入力ではメモリ消費に注意)

コレクション特性(collectionカテゴリの追加事項)

  • チェーン可:可(非破壊)
  • 破壊的/非破壊:非破壊
  • キー保持:保持(左のキーが優先)
  • LazyCollection 対応:非対応(等価処理には一度 collect() で実体化する必要あり。遅延性は失われる)
  • 計算量の目安:O(n + m)
  • 入出力対応(小例)
    • collect(['a'=>1, 'b'=>2])->union(['b'=>9,'c'=>3])['a'=>1,'b'=>2,'c'=>3]
    • collect([1,2])->union([2,3])[1,2](数値キー 0,1 が左優先のため増えない)

使用例

最小例

<?php

use Illuminate\Support\Collection;

$base  = collect(['a' => 1, 'b' => 2]);
$extra = ['b' => 99, 'c' => 3];

$result = $base->union($extra);

// 結果: ['a' => 1, 'b' => 2, 'c' => 3]
// 'b' は左優先で 2 のまま、'c' だけ追加

実務例:固定デフォルトを崩さずにユーザー入力を“追記”

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Collection;

function buildOptions(Request $request): Collection
{
    // システム固定値(上書き不可)
    $locked = collect([
        'timeout' => 30,
        'retry'   => 2,
        'region'  => 'jp-east',
    ]);

    // ユーザーが足せる拡張項目(上記キーは無視される)
    $userAppendables = $request->only(['tags', 'note', 'priority']);

    // union なら固定値を守りつつ、未知キーだけ追記できる
    return $locked->union($userAppendables);
}

よくある落とし穴・注意

  • 値のユニーク結合ではない:キーで比較します。値ベースで重複排除したいなら concat()->unique()、順序を保ちたいなら values() も検討。
  • 数値キーの罠[1,2] ∪ [2,3][1,2] のまま。右の 0,1 キーは既に存在するため無視されます。
  • 深い配列は非再帰:ネスト配列のマージはしません。階層をマージしたいなら Arr::dot() で平坦化してから統合する、または merge と個別ロジックを併用。
  • LazyCollection 非対応:遅延で巨大データを扱う場合は collect($lazy) により実体化が必要(メモリ増)。

代替・関連APIとの比較

  • union:左優先で“存在しないキーだけ追加”。上書き禁止が要件なら最適。
  • merge:連想キーは右が上書き、数値キーは末尾に追加・再採番。設定の上書きや追記に便利。
  • concat:キー無視で末尾に連結。値ベースのユニーク化は concat()->unique()
  • replace:連想キーを右で置換(数値キーはそのまま)。
  • intersectByKeys:キー集合の共通部分だけを取得。

選定基準

  • 既存値を守りたい → union
  • 右で上書き・追記したい → merge
  • 単純に後ろへ付けたい → concat

テスト例(Pest)

<?php

use Illuminate\Support\Collection;

it('keeps left values and adds only missing keys', function () {
    $left  = collect(['a' => 1, 'b' => 2, 0 => 10]);
    $right = collect(['b' => 99, 'c' => 3, 1 => 30, 0 => 999]);

    $u = $left->union($right);

    expect($u->all())->toBe([
        'a' => 1,    // 左優先
        'b' => 2,    // 左優先
        0   => 10,   // 左優先(数値キーも同様)
        'c' => 3,    // 新規キーだけ追加
        1   => 30,   // 数値キー1は未使用だったため追加
    ]);
});

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

症状/エラー原因対処
値ベースでユニーク結合できないunionキー結合concat()->unique() へ置換。順序維持は values() 併用
右の値で上書きされないunion は左優先で上書きしないmerge を使用(連想キーは右が上書き)
連番配列が増えない数値キー 0..n が左に存在し、右は無視された連番配列なら concat()->unique() を検討
大規模データでメモリが厳しいunion は新インスタンス生成で全要素保持検索・フィルタを先に掛けて要素数を削減、Lazy が必要なら設計を見直す

参考リンク

レン (Wren)

こんにちは。レンです。

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

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

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

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

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

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