> pick | shuffle | pair <

// リストを貼り付けて、当選者を選んだり、順序をシャッフルしたり、人をグループに分けたり - すべてブラウザ内で完結

[PICK_N]

N件のランダム抽出

リストから任意の人数の当選者を抽出します。重複なしでユニークな当選者を選ぶか、重複ありで重み付け風の抽選を行えます。

[SHUFFLE]

偏りのないフィッシャー・イェーツ・シャッフル

古典的なクヌースのシャッフルでリスト全体を並べ替えます。すべての順列が等しく起こり得ます - 安易なソートのごまかしはありません。

[PAIRS]

グループに分ける

名簿をペア、トリオ、または任意のグループサイズに分割します。ペアワーク、コードレビューのローテーション、シークレットサンタのペア決めに最適です。

[SEEDED]

シードによる再現性

シード文字列を指定すると決定論的な抽選になります。同じシードと同じリストなら常に同じ結果が得られ、共有・検証が可能です。

// ランダム抽選について

仕組み:

このツールはフィッシャー・イェーツ(別名クヌース)シャッフルを使用します。配列を最後のインデックスから先頭へたどり、各ステップで現在の要素を一様にランダムに選んだより前のインデックスの要素と交換します。これによりO(n)時間で偏りのない一様な順列が得られます。安易な手法 array.sort(() => Math.random() - 0.5) は偏ります。JavaScriptのソート比較子は推移的でなければならないためで、ランダムな比較子はこれに違反して分布を歪めます。シードなしの抽選では window.crypto.getRandomValues からエントロピーを取得します。シード文字列を指定すると、cyrb53でハッシュして53ビット整数にし、mulberry32 PRNGを駆動するため、同一のシードは同一で再現可能な結果を生成します。

アルゴリズム:

for i = n-1 down to 1: j = randInt(0, i); swap(a[i], a[j]) - unbiased Fisher-Yates

標準と参考文献:

  • >Web Crypto API (W3C) - 暗号論的に強い乱数のための crypto.getRandomValues
  • >フィッシャー・イェーツ・シャッフル(1938年)、ドナルド・クヌースが The Art of Computer Programming 第2巻で広めた
  • >mulberry32 - Tommy Ettinger による小型で高速かつ良好に分布するシード対応PRNG
  • >cyrb53 - bryc による53ビット文字列ハッシュ。シード文字列を数値のPRNG状態に変換するために使用

よくある用途:

  • >プレゼント企画、抽選会、応募者からのランダムな当選者の決定
  • >教室での名前抽選や生徒の指名選出
  • >スポーツチームのペア決め、ペアワークアウト、トーナメント組み合わせ
  • >エンジニアリングチーム全体でのコードレビュー担当者の割り当て
  • >A/Bテストのサンプル選定やランダム化された調査コホート
  • >シークレットサンタのペア、ギフト交換、チームランチの相棒
  • >QA向けのランダムなテスト入力やファジングのシード
  • >グループでの意思決定や引き分けの解消
  • >模擬陪審の選定やランダム化された面接パネル
  • >コミュニティイベントや賞品のための抽選形式の抽せん

関連ツール:

  • >乱数ジェネレーター — テキストベースの相棒:同じシード再現性のプリミティブで範囲内の数を選びます
  • >UUIDジェネレーター — リストからの当選者ではなく、一意で不透明なIDが必要なときのランダムなv4識別子
  • >パスワードジェネレーター — トークンや認証情報向けに文字プールを制御できる暗号論的にランダムな文字列
  • >randompickerwheel.app — このテキスト抽選を補完するルーレットUI。ライブ観客の抽選、教室での指名、画面上での発表に最適

// 抽選の例

プレゼント企画 — 50件の応募から3名の当選者を選ぶ

> input:

alice@x.com
bob@x.com
carlos@x.com
…(合計50行)

> config:

モード=Pick N, 数=3, 重複を許可=off, シード=(空)

> output:

1. carlos@x.com
2. priya@x.com
3. wei@x.com

発表順を決めるため10名のリストをシャッフル

> input:

Alice
Bob
Charlie
Dana
Evelyn
Farouk
Gabriela
Hiroshi
Isabella
Jamal

> config:

モード=Shuffle, シード=(空)

> output:

1. Hiroshi
2. Alice
3. Farouk
4. Jamal
5. Dana
6. Evelyn
7. Bob
8. Isabella
9. Gabriela
10. Charlie

12名の生徒のクラスを2人ずつのグループに分ける

> input:

S01
S02
S03
S04
S05
S06
S07
S08
S09
S10
S11
S12

> config:

モード=Pair Up, グループサイズ=2, シード=class-2026-05-02

> output:

グループ 1: S07, S02
グループ 2: S11, S04
グループ 3: S09, S12
グループ 4: S01, S06
グループ 5: S03, S10
グループ 6: S08, S05

再現可能なシード付き抽選 — 同じシードで2回実行し、同じ当選者を得る

> input:

alpha
bravo
charlie
delta
echo
foxtrot
golf
hotel

> config:

モード=Pick N, 数=2, シード=launch-day, 重複を許可=off

> output:

実行 1: 1. echo
        2. bravo
実行 2: 1. echo
        2. bravo  (同一 — シード付き)

// なぜ安易な .SORT() は偏るのか

よくある1行のシャッフルが arr.sort(() => Math.random() - 0.5) です。エレガントに見え、1行で書け、ランダムに感じられます — しかし結果として得られる順列の分布は一様からはほど遠いものです。ECMAScript仕様は比較関数が決定論的かつ推移的であることを要求します。すなわち a < b かつ b < c ならば a < c です。コイントスのような比較子はこの契約に違反し、エンジンのソート実装は比較ペアを一様でないパターンで訪れます。

V8(Chrome、Node)はTimsortを使い、古いエンジンはquicksortやmergesortを使っていました。各実装は異なる比較ペアの部分集合を訪れ、キャッシュされた比較を異なる方法で再利用します。Mike Bostock が実証的に示したように(bost.ocks.org/mike/shuffle/compare.html)、安易なソートは強く偏った出力を生み、一部の順列が他より何倍も頻繁に現れます — プレゼント企画、A/Bバケット、公平でなければならない抽選には受け入れられません。

正しいアルゴリズムはフィッシャー・イェーツ(クヌースのシャッフル)です。配列を最後のインデックスから先頭までたどり、各ステップで現在の要素をインデックス0..iの中から一様にランダムに選んだものと交換します。O(n)で動作し、追加領域はO(1)で、すべての順列を等確率で生成することが証明できます。

// BAD: NOT uniformly random
const shuffled = arr.sort(() => Math.random() - 0.5);

// GOOD: Fisher-Yates (Knuth) shuffle
function shuffle(arr) {
  const a = arr.slice();
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

// 自分で実装する

独自の抽選ツールを作りたい、あるいは当方のものを監査したいですか? これはこのページが使用するまさにそのプリミティブです — 小さく、依存関係がなく、PICKをクリックしたときにブラウザで動くものと同一です。Nodeスクリプトや別のウェブアプリにそのままコピーしてください。

// Fisher-Yates shuffle (uniform, O(n))

function shuffle(arr, rng = Math.random) {
  const a = arr.slice();
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(rng() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

// Pick N without replacement (shuffle then slice)

function pickN(arr, n, rng = Math.random) {
  if (n > arr.length) {
    throw new Error('n exceeds list size');
  }
  return shuffle(arr, rng).slice(0, n);
}

// mulberry32 seeded PRNG + cyrb53 string hash

// cyrb53: turn a seed string into a 53-bit integer
function cyrb53(str, seed = 0) {
  let h1 = 0xdeadbeef ^ seed;
  let h2 = 0x41c6ce57 ^ seed;
  for (let i = 0, ch; i < str.length; i++) {
    ch = str.charCodeAt(i);
    h1 = Math.imul(h1 ^ ch, 2654435761);
    h2 = Math.imul(h2 ^ ch, 1597334677);
  }
  h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
       Math.imul(h2 ^ (h2 >>> 13), 3266489909);
  h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
       Math.imul(h1 ^ (h1 >>> 13), 3266489909);
  return 4294967296 * (2097151 & h2) + (h1 >>> 0);
}

// mulberry32: tiny seeded PRNG -> [0, 1)
function mulberry32(a) {
  return function () {
    a |= 0; a = (a + 0x6D2B79F5) | 0;
    let t = a;
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

// Build a seeded picker:
const h = cyrb53('my-seed', 1);
const state = (h ^ Math.floor(h / 4294967296)) >>> 0;
const rng = mulberry32(state);
const winners = pickN(['alice', 'bob', 'carlos'], 2, rng);

>> よくある質問

Q: ランダム性はどのように生成されますか?

A: シードが指定されていない場合、Web Crypto APIに基づくブラウザの暗号論的に安全な乱数生成器である window.crypto.getRandomValues を使用します。これは暗号鍵やトークンに使われるのと同じエントロピー源であり、抽選やシャッフルには十分すぎる強度です。シードを指定すると、cyrb53文字列ハッシュで53ビットの状態を決定論的に導出し、それを mulberry32 PRNG に入力するため、抽選は再現可能になります。

Q: シードを使って同じ結果を2回得られますか?

A: はい。SEEDフィールドに任意の文字列を入力してください - 日付、コンテスト名、ハッシュ、何でも構いません。同じシードを同じ入力リストおよび同じモードと組み合わせれば、常にまったく同じ出力が生成されます。これは、シードを事前に公開して参加者に抽選を検証してもらいたい透明性のあるプレゼント企画や、マシン間で再現可能である必要があるエンジニアリングのローテーションにおいて非常に有用です。

Q: Pick N と Shuffle の違いは何ですか?

A: Pick N はリストからサイズNの部分集合を選び、任意で復元抽出(重複を許可)も可能です。Shuffle はリスト全体を並べ替えて返します - 項目が落とされたり繰り返されたりすることはなく、ただ並び替えられるだけです。多数の応募から数名の当選者だけが欲しいときは Pick N を使い、各項目が引き続き参加するものの新しいランダムな順序になる必要があるとき(発表のキューやプレイリストなど)は Shuffle を使ってください。

Q: array.sort(() => Math.random() - 0.5) は本当にランダムですか?

A: いいえ、偏っています。ECMAScript仕様はソート比較子が決定論的かつ推移的であることを要求します(a < b かつ b < c ならば a < c)。ランダムな比較子はこの契約に違反し、異なるJavaScriptエンジンは異なる基盤ソートアルゴリズム(TimSort、mergesort、quicksort)を実行し、それぞれ異なる方法でランダム比較子と相互作用します。その結果、一部の順列が他より大幅に多く現れる一様でない分布になります。フィッシャー・イェーツが正しいアルゴリズムです。

Q: 奇数件のリストをペアにできますか?

A: はい。Pair Up モードはフィッシャー・イェーツでリストをシャッフルし、選択したグループサイズで分割します。合計が均等に割り切れない場合、最後のグループは小さくなり、出力では余りのグループとして明確にラベル付けされます。奇数のリストでは、単独の項目を受け入れる、グループサイズを増やす、または抽選前に「bye」のようなプレースホルダー名を追加することができます。

Q: 私のリストはどこかにアップロードされますか?

A: いいえ。このツールは100%クライアントサイドです - あなたのリスト、シード、出力がブラウザから出ることは決してありません。サーバー呼び出しも、ログ記録も、入力に対する分析もありません。ページの読み込み後にインターネットを切断しても、すべてのボタンは引き続き動作します。ページを更新すればデータは完全に消えます。

Q: このツールにルーレット形式の視覚版はありますか?

A: アニメーション、効果音、大きな視覚的演出を備えたインタラクティブな名前ルーレット体験については、randompickerwheel.app をご覧ください。ライブ観客の抽選や画面共有に特化した補完的な製品です。このページはテキスト優先の抽選ツールで、大量のリスト、再現可能なシード付き抽選、CSVエクスポート、ペア決めに重点を置いています - プレゼンテーションではなく素早い決定論的な答えが必要なときに役立ちます。

// OTHER LANGUAGES