2010-02-04 7 views
8

Mam kilka dużych plików o stałej szerokości i muszę upuścić wiersz nagłówka.Ruby: Czy istnieje coś takiego jak drop # #, który zwraca moduł wyliczający zamiast tablicy?

Śledzenie iteratora nie wydaje się bardzo idiomatyczne.

# This is what I do now. 
File.open(filename).each_line.with_index do |line, idx| 
    if idx > 0 
    ... 
    end 
end 

# This is what I want to do but I don't need drop(1) to slurp 
# the file into an array. 
File.open(filename).drop(1).each_line do { |line| ... } 

Co to jest idiom Ruby?

Odpowiedz

5

Jeśli potrzebujesz go więcej niż raz, możesz napisać rozszerzenie do Enumerator.

class Enumerator 
    def enum_drop(n) 
    with_index do |val, idx| 
     next if n == idx 
     yield val 
    end 
    end 
end 

File.open(testfile).each_line.enum_drop(1) do |line| 
    print line 
end 

# prints lines #1, #3, #4, … 
+0

To jest bardzo ładne (i rubyistyczne) rozwiązanie. Jeśli nie lubisz tego języka, zmień go. Byłem pewien, że to, co chciałem zrobić, było tak powszechne, że byłby już istniejący idiom lub funkcja. Minęły dwa dni, odkąd zapytałem, więc przypuszczam, że nie. enum_cons i enum_slice istnieją, więc może nazwa enum_drop lepiej pasuje do stdlib. Dziękuję Ci. –

+0

Masz rację. To brzmi lepiej. Zmieniono go na 'enum_drop'. – Debilski

+0

Czy nie byłoby bardziej jak: ... with_index (n) {| val, idx | yield val} ... –

1

Off górze mojej głowie, ale jestem pewien, że z jakiegoś dalszych badań jest bardziej elegancki sposób

File.open(filename).each_line.to_a[1..-1].each{ |line|... } 

... Ok zarysowania że zrobił trochę badań i to może być lepiej

File.open(filename).each_line.with_index.drop_while{ |line,index| index == 0 }.each{ |line, index| ... } 
+0

To będzie chętnie ocenić wyliczający do tablicy przed iteracji po liniach, powodując cały plik do slurped do pamięci na raz. –

+0

Tak, uświadomiłem to sobie. Zaktualizowałem go, używając wyłącznie modułów wyliczających. – Farrel

+0

Nie jestem pewien, czy funkcja drop_while będzie działała zgodnie z dokumentami, ale zwraca także tablicę ... – Farrel

7

to nieznacznie neater:

File.open(fname).each_line.with_index do |line, lineno| 
    next if lineno == 0 
    # ... 
end 

lub

io = File.open(fname) 
# discard the first line 
io.gets 
# process the rest of the file 
io.each_line {|line| ...} 
io.close 
+0

Podoba mi się tutaj drugie rozwiązanie Glenna, nawet jeśli nie używa ono bardziej wyglądającego zamknięcia 'File.open() do ... end'. – bta

1

Wątpię, czy to jest idiomatyczne, ale to proste.

f = File.open(filename) 
f.readline 
f.each_line do |x| 
    #... 
end 
+0

Przepraszam, widzę, że podczas komponowania tego Glenn mnie do tego pobił. – Shadowfirebird

2

Teraz, gdy uzyskałeś rozsądne odpowiedzi, oto zupełnie inny sposób radzenia sobie z tym.

class ProcStack 
    def initialize(&default) 
    @block = default 
    end 
    def push(&action) 
    prev = @block 
    @block = lambda do |*args| 
     @block = prev 
     action[*args] 
    end 
    self 
    end 
    def to_proc 
    lambda { |*args| @block[*args] } 
    end 
end 
#... 
process_lines = ProcStack.new do |line, index| 
    puts "processing line #{index} => #{line}" 
end.push do |line, index| 
    puts "skipping line #{index} => #{line}" 
end 
File.foreach(filename).each_with_index(&process_lines) 

Po raz pierwszy nie jest to idiomatyczne, ani strasznie intuicyjne, ale jest zabawne!

+0

w rzeczywistości, jeśli używasz kolejki, jest dużo bardziej przejrzysta (mniej odwrócona logika). – rampion

1

Myślę, że masz rację z Enumerator i upuść (1). Z jakiegoś dziwnego powodu, podczas gdy Enumerable definiuje #drop, Enumerator tego nie robi. Oto praca Enumerator # drop:

class Enumerator 
    def drop(n_arg) 
     n = n_arg.to_i # nil becomes zero 
     raise ArgumentError, "n must be positive" unless n > 0 
     Enumerator.new do |yielder| 
     self.each do |val| 
      if n > 0 
      n -= 1 
      else 
      yielder << val 
      end 
     end 
     end 
    end 
    end 
Powiązane problemy