2010-02-04 15 views
8

Tengo algunos archivos grandes de ancho fijo y necesito soltar la línea del encabezado.Ruby: ¿Hay algo así como Enumerable # drop que devuelve un enumerador en lugar de una matriz?

Seguir la pista de un iterador no parece muy idiomático.

# 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| ... } 

¿Qué es el modismo de Ruby para esto?

Respuesta

5

Si lo necesita más de una vez, puede escribir una extensión en 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

Esta es una solución muy buena (y rubí). Si no te gusta el idioma, cámbialo. Estaba seguro de que lo que quería hacer era tan común que existiría un modismo o una función ya existente. Han pasado dos días desde que pregunté, así que supongo que no. enum_cons y enum_slice existen así que tal vez el nombre enum_drop se ajustaría mejor al stdlib. Gracias. –

+0

Tienes razón. Eso suena mejor. Cambió a 'enum_drop'. – Debilski

+0

¿No sería más como: ... with_index (n) {| val, idx | rendimiento val} ... –

1

De la parte superior de mi cabeza, pero estoy seguro de que con un poco más investigación que hay una manera más elegante

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

cero Está bien que ... hizo un poco de investigación y esto podría ser mejor

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

que evaluará ansiosamente el empadronador a un arreglo antes de iterar sobre las líneas, causando todo el archivo para ser sorbido a la memoria a la vez. –

+0

Sí, me di cuenta de eso. Lo he actualizado usando nada más que enumeradores. – Farrel

+0

No estoy seguro si drop_while funcionará de acuerdo con los documentos, también devuelve una matriz ... – Farrel

7

Ésta es ligeramente más ordenado:

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

o

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

Me gusta la segunda solución de Glenn aquí, incluso si no utiliza el aspecto más limpio 'File.open() do ... end' closure. – bta

1

Dudo que esto sea idiomático, pero es simple.

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

Pido disculpas, veo que mientras escribía esto, Glenn me ganó. – Shadowfirebird

2

Ahora que ha obtenido respuestas razonables, esta es una forma completamente diferente de manejarlo.

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) 

No es ni idiomático, ni terriblemente intuitivo la primera vez, pero es divertido!

+0

en realidad, si utiliza una cola, es mucho más clara (lógica menos invertida) – rampion

1

Creo que va por buen camino con el Enumerador y soltar (1). Por alguna extraña razón, mientras que Enumerable define #drop, el Enumerator no. Aquí es un enumerador # caída de trabajo:

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 
Cuestiones relacionadas