Ruby:从文本文件中选择随机行的优雅方法是什么?

Tre*_*res 13 ruby io file

我已经看到了Ruby的一些非常漂亮的例子,我试图改变我的想法,以便能够制作它们而不仅仅是欣赏它们.这是我从文件中挑选随机行的最佳方法:

def pick_random_line
  random_line = nil
  File.open("data.txt") do |file|
    file_lines = file.readlines()
    random_line = file_lines[Random.rand(0...file_lines.size())]
  end 

  random_line                                                                                                                                                               
end 
Run Code Online (Sandbox Code Playgroud)

我觉得有必要以更短,更优雅的方式做到这一点,而不将整个文件的内容存储在内存中.在那儿?

Dav*_*acs 37

Ruby Array类中已经内置了一个随机入口选择器:sample().

def pick_random_line
  File.readlines("data.txt").sample
end
Run Code Online (Sandbox Code Playgroud)

  • 警告:如果文件很大,你会受苦. (5认同)
  • 请注意,对于那些仍在使用Ruby 1.8的人来说,`sample`被称为`choice`然后. (2认同)

Mar*_*eed 13

你可以在不存储除随机线的当前候选者之外的任何东西的情况下进行.

def pick_random_line
  chosen_line = nil
  File.foreach("data.txt").each_with_index do |line, number|
    chosen_line = line if rand < 1.0/(number+1)
  end
  return chosen_line
end
Run Code Online (Sandbox Code Playgroud)

所以选择第一行的概率为1/1 = 1; 选择第二行的概率为1/2,因此它保留第一行的一半时间和切换到第二行的一半时间.

然后选择第三行的概率为1/3 - 所以它选择它的时间的1/3,另外2/3的时间它保留它所选择的前两个中的任何一个.由于他们每个人都有50%的机会被选为第2行,所以他们每人都有1/3的机会被选为第3行.

等等.在第N行,1-N的每一行都有一个偶数1/N的机会被选中,并且一直保持在文件中(只要文件不是那么大,1 /(文件中的行数) )小于epsilon :)).而且你只需要通过一个文件,一次不会存储两行以上.

编辑你不会用这个算法得到一个真正简洁的解决方案,但你可以把它变成一个单行,如果你想:

def pick_random_line
  File.foreach("data.txt").each_with_index.reduce(nil) { |picked,pair| 
    rand < 1.0/(1+pair[1]) ? pair[0] : picked }
end
Run Code Online (Sandbox Code Playgroud)