遠藤です。

議論が大分入り組んで来たので、一旦現在の API とその実装の案を
まとめてみました。sample_each は each_sample に改名してます。


Array#sample([size, [opt]])
  - API
    - size が省略されたら 1 つサンプリングして返す
    - size が与えられたら size 分だけ非復元抽出して配列で返す
    - opt の意味:
      weight: proc or array
      random: Random instance

  - 実装
    - weight が省略されたら現在の実装と同じ
    - weight が与えられたら akr さんの方法 [ruby-dev:42844]

Array#choice([size, [opt]])
  - API
    - size が省略されたら 1 つサンプリングして返す
    - size が与えられたら size 分だけ復元抽出して配列で返す
    - opt は Array#sample と同じ

  - 実装
    - 乱数選択を size 回繰り返すだけ (weight が与えられたら考慮する)
    - Walker's alias method は使わない (size が小さい時は不利になる
      し、size が大きい場合だけ使うのも乱数の再現性が壊れるからダメ)

Array#each_sample([opt])
  - API
    - サンプリングして yield を繰り返す (全部サンプリングしたら終了)
    - ブロックを省略したら Enumerator を返す
    - opt は Array#sample と同じ

  - 実装
    - weight が省略されたら現在の実装と似た感じ
    - weight が与えられたら akr さんの方法 (ちょっと非効率になる?)

Array#each_choice([opt])
  - API
    - サンプリングして yield を無限に繰り返す
    - ブロックを省略したら Enumerator を返す
    - opt は Array#sample と同じ

  - 実装
    - weight が省略されたら乱数選択を無限に繰り返す
    - weight が与えられたら Walker's alias method を無限に繰り返す


それぞれの例
  - %(大吉 中吉 小吉 凶).sample    #=> 等確率にどれか
  - %(大吉 中吉 小吉 凶).sample(4) #=> shuffle と同じ
  - %(大吉 中吉 小吉 凶).sample(weight: [1000, 100, 10, 1])
      #=> 重み付きでどれか (大吉が出やすい)
  - %(大吉 中吉 小吉 凶).sample(4, weight: [1000, 100, 10, 1])
      #=> 重み付きでどれか、の配列 (["大吉", "中吉", "小吉", "凶"] が最も出やすい)
  - %(大吉 中吉 小吉 凶).sample(4, weight: proc {|x| ... } )
      #=> 重み付きでどれか、の配列 (重みは proc が返した値)

  - %(大吉 中吉 小吉 凶).choice    #=> 等確率にどれか
  - %(大吉 中吉 小吉 凶).choice(4) #=> choice を 4 回繰り返すのに相当
  - %(大吉 中吉 小吉 凶).choice(weight: [1000, 100, 10, 1])
      #=> 重み付きでどれか (大吉が出やすい)
  - %(大吉 中吉 小吉 凶).choice(4, weight: [1000, 100, 10, 1])
      #=> 重み付きでどれか、の配列 (["大吉", "大吉", "大吉", "大吉"] が最も出やすい)

  - %(大吉 中吉 小吉 凶).each_sample.first  #=> sample と同じ
  - %(大吉 中吉 小吉 凶).each_sample.to_a   #=> shuffle と同じ
  - %(大吉 中吉 小吉 凶).each_sample(weight: [1000, 100, 10, 1]).take(4)
      #=> 重み付きでどれか、の配列 (["大吉", "中吉", "小吉", "凶"] が最も出やすい)

  - %(大吉 中吉 小吉 凶).each_choice.first  #=> choice と同じ
  - %(大吉 中吉 小吉 凶).each_choice.to_a   #=> choice(4) と同じ
  - %(大吉 中吉 小吉 凶).each_choice(weight: [1000, 100, 10, 1]).take(4)
      #=> 重み付きでどれか、の配列 (["大吉", "大吉", "大吉", "大吉"] が最も出やすい)

-- 
Yusuke Endoh <mame / tsg.ne.jp>