Самый быстрый способ пропустить строки при разборе файлов в Ruby? - PullRequest
9 голосов
/ 19 февраля 2011

Я пытался найти это, но не смог найти много. Кажется, что-то, о чем, вероятно, спрашивали раньше (много раз?), Поэтому я прошу прощения, если это так.

Мне было интересно, каким был бы самый быстрый способ анализа определенных частей файла в Ruby. Например, предположим, что я знаю , информация, которую я хочу получить для конкретной функции, находится между строками 500 и 600, скажем, файла в 1000 строк. (очевидно, этот вопрос предназначен для больших файлов, я просто использую эти меньшие числа в качестве примера), так как я знаю, что это не будет в первой половине, есть ли быстрый способ игнорировать эту информацию

В настоящее время я использую что-то вроде:

while  buffer = file_in.gets and file_in.lineno <600
  next unless file_in.lineno > 500
  if buffer.chomp!.include? some_string
    do_func_whatever
  end
end

Это работает, но я просто не могу не думать, что это может работать лучше.

Я очень новичок в Ruby и мне интересно изучать новые способы ведения дел в нем.

Ответы [ 4 ]

11 голосов
/ 19 февраля 2011
file.lines.drop(500).take(100) # will get you lines 501-600

Как правило, вы не можете избежать чтения файла с самого начала до интересующей вас строки, поскольку каждая строка может иметь разную длину.Единственное, чего вы можете избежать, это загрузить весь файл в большой массив.Просто читайте построчно, считая и отбрасывая их, пока не достигнете того, что ищете.Очень похоже на ваш собственный пример.Вы можете просто сделать его более рубиновым.

PS.комментарий Жестянщика заставил меня поэкспериментировать.Хотя я не нашел причины, по которой drop загружал бы весь файл, проблема действительно есть: drop возвращает остальную часть файла в массиве.Вот как этого можно избежать:

file.lines.select.with_index{|l,i| (501..600) === i}

PS2: Код выше, хотя и не создает огромный массив, выполняет итерацию по всему файлу, даже по строкам ниже 600. :( Вот третья версия:

enum = file.lines
500.times{enum.next} # skip 500
enum.take(100) # take the next 100

или, если вы предпочитаете FP:

file.lines.tap{|enum| 500.times{enum.next}}.take(100)

В любом случае, хороший смысл этого монолога заключается в том, что вы можете научиться нескольким способам итерации файла.;)

1 голос
/ 19 февраля 2011

Я не знаю, существует ли эквивалентный способ сделать это для строк, но вы можете использовать seek или offset аргумент для объекта ввода-вывода, чтобы «пропустить» байты.

См. IO # seek или см. IO # open для получения информации об аргументе смещения.

0 голосов
/ 19 февраля 2011

Вы можете использовать IO # readlines , который возвращает массив со всеми строками

IO.readlines(file_in)[500..600].each do |line| 
  #line is each line in the file (including the last \n)
  #stuff
end

или

f = File.new(file_in)
f.readlines[500..600].each do |line| 
  #line is each line in the file (including the last \n)
  #stuff
end
0 голосов
/ 19 февраля 2011

Звучит как rio .Он предоставляет вам метод lines().

...