この機能は、あなたが必要とする正確に何をしてもDaveのと短いです。
これはワンライナーではありません。しかし、それは任意のサイズのテキストファイル(ゼロサイズ、多分:)を除いて動作します。
def random_line(filename)
blocksize, line = 1024, ""
File.open(filename) do |file|
initial_position = rand(File.size(filename)-1)+1 # random pointer position. Not a line number!
pos = Array.new(2).fill(initial_position) # array [prev_position, current_position]
# Find beginning of current line
begin
pos.push([pos[1]-blocksize, 0].max).shift # calc new position
file.pos = pos[1] # move pointer backward within file
offset = (n = file.read(pos[0] - pos[1]).rindex(/\n/)) ? n+1 : nil
end until pos[1] == 0 || offset
file.pos = pos[1] + offset.to_i
# Collect line text till the end
begin
data = file.read(blocksize)
line.concat((p = data.index(/\n/)) ? data[0,p.to_i] : data)
end until file.eof? or p
end
line
end
それを試してみてください。
filename = "huge_text_file.txt"
100.times { puts random_line(filename).force_encoding("UTF-8") }
無視できる(私見)欠点:それは
長いライン、高いチャンスを選んだことでしょうが。
では、 "\ r"という行区切り文字(Windows固有)は考慮されていません。 Unixスタイルの行末でファイルを使用する!
これは、「これをRuby_でどうやって行うのですか」の質問、または「これをO(N)space_未満の質問で行う方法」の詳細ですか?後者の場合は、[リザーバサンプリング](http://gregable.com/2007/10/reservoir-sampling.html)を調べてください。 – zwol
私の簡単な実装は、ファイル内のランダムな位置を探して、改行に進むことです。 –
@SamSaffronこれは、すべての行がまったく同じ長さでない限り、一様にランダムな行を与えません。 – zwol