random — コレクションからランダム取得

未分類
  • カテゴリ: collection
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN: Illuminate\Support\Collection::random
  • 関連: shuffle, take, first, sample
  • 変更履歴: 既存メソッド(挙動の大きな変更なし)

要点(TL;DR)

  • コレクションから ランダムに1件または複数件 を取得する
  • 例: $item = collect([1,2,3])->random();
  • 罠:
    • 件数指定が要素数超過だと 例外
    • 1件取得時は Collectionではなく値 が返る
    • LazyCollection非対応

概要

random() は、コレクション内の要素をランダムに取得するためのメソッドです。
UIのおすすめ表示、テストデータ抽出、サンプル取得など、順序に意味を持たせたくない場面で使います。

構文 / シグネチャ

random(int $number = null): mixed

引数

引数必須既定値説明
$numberint任意null取得する件数
  • 戻り値
    • $number 未指定: 要素そのもの(mixed)
    • $number 指定: Collection
  • 例外/副作用
    • 要素数 < $number の場合 InvalidArgumentException

使用例

最小例

use Illuminate\Support\Collection;

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

$item = $col->random(); // string

複数件取得

$items = $col->random(2); // Collection

実務例(おすすめ記事を3件表示)

use App\Models\Post;

$posts = Post::query()
    ->where('published', true)
    ->get()
    ->random(3);

inRandomOrder()との使い分け(DB側でランダム抽出したい場合)

Collection::random() は、すでにメモリ上にあるコレクションからランダムに取り出すメソッドです。一方、Eloquentのクエリビルダには inRandomOrder() という別のメソッドがあり、DB側でランダムに並び替えてから取得できます。件数の多いテーブルから1〜数件だけ欲しい場合は、全件を get() してから random() するより inRandomOrder() の方が効率的です。

use App\Models\Post;

// 非効率: 全件をメモリに読み込んでからランダム抽出
$post = Post::all()->random();

// 効率的: DB側でランダムに並び替えて1件だけ取得
$post = Post::inRandomOrder()->first();

// 複数件(DB側でランダム抽出)
$posts = Post::inRandomOrder()->limit(3)->get();
方法処理される場所向いているケース
Collection::random()PHP(メモリ上)既に取得済みの配列・コレクションから抽出したい
Query::inRandomOrder()DB(SQLのORDER BY RAND()相当)大きいテーブルから直接1〜数件だけ欲しい

ただし inRandomOrder() はテーブル件数が多いと ORDER BY RAND() のコストが無視できなくなるため、大規模テーブルでは注意が必要です。

よくある落とし穴・注意

  • 戻り値の型に注意$col->random(); // 値 $col->random(1); // Collection
  • 件数超過は例外collect([1,2])->random(3); // 例外
  • 空のコレクションでも例外collect([])->random(); // InvalidArgumentException
    事前に isEmpty で件数を確認するか、try/catchで握りつぶさず空配列時の分岐を用意する
  • random(0)は例外にならないcollect([1,2,3])->random(0); // 空のCollection
    件数0は「0件取得」として扱われ、要素数超過の例外にはならない(0nullの挙動の違いに注意)
  • LazyCollectionでは使えない
    • 必要なら ->collect()->random() に変換

ランダムな文字列生成(Str::random)と混同しない

「laravel random」で検索すると、コレクションからの要素抽出ではなくランダムな文字列(トークンやパスワード)を生成したい場合にたどり着くこともあります。本記事のCollection::random()とは別物なので、目的に応じて使い分けてください。

目的使うもの
コレクションから要素をランダム抽出Collection::random()(本記事)collect([1,2,3])->random()
ランダムな文字列(トークン等)を生成Illuminate\Support\Str::random()Str::random(32) // 32文字のランダム文字列

代替・関連APIとの比較

メソッド特徴選定基準
random完全ランダム単発・抽出
shuffle全体をシャッフル並び替えたい
take先頭から取得順序重視
sample統計的サンプリング大量データ

テスト例(Pest)

it('returns random item', function () {
    $col = collect([1, 2, 3]);
    $item = $col->random();

    expect($col)->toContain($item);
});

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

症状/エラー原因対処
InvalidArgumentException件数超過件数を制限
型エラー1件取得で値が返る(array)random(1)->first()

よくある質問(FAQ)

Q. テストでrandom()の結果を固定(再現)したい場合は?

A. random() 自体にシード値を指定するオプションはありません。テストで結果を固定したい場合は、random() を使わずに要素数1件のコレクションに対して呼び出すか、対象を明示的に指定してアサーションする(「返り値がコレクションに含まれているか」を検証する)方法が確実です。上記のPestの例のように toContain() で検証するのが定番です。

Q. 重複なしで複数件をランダムに取得したい場合は?

A. random($number) で複数件を指定すると、コレクション内で重複しない $number 件がランダムに返されます(同じ要素が2回選ばれることはありません)。重複ありで抽選したい場合は random() をループで複数回呼び出す必要があります。

Q. EloquentモデルをDB側でランダムに1件取得するには?

A. Model::inRandomOrder()->first() を使います。Collection::random() はメモリ上のコレクションが対象のため、全件取得してから絞り込むより inRandomOrder() でDB側にランダム抽出させる方が効率的です。詳細は本記事の「inRandomOrder()との使い分け」を参照してください。

関連記事

参考リンク

レン (Wren)

こんにちは。レンです。

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

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

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

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

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

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