Created
August 29, 2016 07:34
-
-
Save maraigue/0dd8d530c6b7dad4a48a5d56096d36bc to your computer and use it in GitHub Desktop.
[Ruby] ArrayじゃなくてEnumerableでsample(ランダムにn要素を選ぶ)を使えるようにする
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# -*- coding: utf-8 -*- | |
# ArrayじゃなくてEnumerableでsample(ランダムにn要素を選ぶ)を使えるようにする。 | |
# 例えば、大きいファイルから1行をランダムに抜き出すなど。 | |
# | |
# 厄介なのは、要素の個数が最初からはわからないこと。 | |
# 作戦としては以下の通り。 | |
# - k個目の要素までを読み込んだとき、そのk個目の要素が選ばれているべき確率は | |
# n/k。なのでその確率で選ばれるかを決める。 | |
# - 一度n個の要素に入っても、後から来たもので上書きされることはある。 | |
# 上書きされる確率は等確率にする。 | |
module Enumerable | |
def sample(n = 1) | |
n = n.to_i | |
if n < 0 | |
raise ArgumentError, "Number of choices must be non-negative" | |
elsif n == 0 | |
return [] | |
end | |
k = 0 | |
stock = [] | |
each do |elem| | |
k += 1 | |
if stock.size < n | |
# まだn個選べていない場合は、単に選ぶ | |
stock << elem | |
else | |
newpos = rand(k) | |
stock[newpos] = elem if newpos < n | |
end | |
end | |
stock | |
end | |
end | |
if $0 == __FILE__ | |
if ARGV.size < 1 | |
STDERR.puts "[Usage of this file]" | |
STDERR.puts "This library implements Enumerable#sample (almost the same as Array#sample, but random number generator cannot be specified)." | |
STDERR.puts "" | |
STDERR.puts "[Usage of this command-line tool]" | |
STDERR.puts "This program samples [Count] lines in the file at random. If no file is specified, do the same for STDIN." | |
STDERR.puts "Usage: enum_random [Count] ([FILES...])" | |
exit | |
end | |
count = Integer(ARGV.shift) | |
ARGF.each_line.sample(count) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment