Here's a way that uses the method Array#sample and several class methods for reading and writing text files that are defined in the IO class. I have made the following assumptions:
- a specified number of lines are to be chosen at random
- the lines chosen at random are to be kept in order
- the entire file is not to be read into memory
- lines to be written to file are not accumulated in memory before being written
Code
def doit(fname_in, fname_out, nbr)
n_lines = File.foreach(fname_in).reduce(0) { |c, _| c+1 }
return nil if n_lines.zero? || nbr.zero?
ndx = [*(0...n_lines)].sample(nbr).sort
f_out = File.open(FNAME_OUT, 'w')
offset = ndx.shift
File.foreach(fname_in).with_index do |line, i|
if i == offset
f_out.write(line)
offset = ndx.shift
end
break unless offset
end
f_out.close
end
Example
FNAME_IN, FNAME_OUT = 'infile', 'outfile'
Let's first create an input file:
lines =<<_
Now
is
the
time
for
all
good
Rubyists
to
put
aside
work
and
watch
the
World
Cup
final
between
Germany
and
Argentina
_
File.write(FNAME_IN, lines) #=> 116
We can confirm the contents of this file with:
File.foreach(FNAME_IN) { |l| puts l }
Now try it:
doit(FNAME_IN, FNAME_OUT, 10)
Let's see what was written. (Drum roll.)
File.foreach(FNAME_OUT) { |l| puts l }
Now
is
the
for
to
aside
watch
World
Cup
final