问题
I have some big fixed-width files and I need to drop the header line.
Keeping track of an iterator doesn't seem very idiomatic.
# 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| ... }
What's the Ruby idiom for this?
回答1:
If you need it more than once, you could write an extension to 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, …
回答2:
This is slightly neater:
File.open(fname).each_line.with_index do |line, lineno|
next if lineno == 0
# ...
end
or
io = File.open(fname)
# discard the first line
io.gets
# process the rest of the file
io.each_line {|line| ...}
io.close
回答3:
Now that you've gotten reasonable answers, here's a completely different way to handle it.
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)
It's neither idiomatic, nor terribly intuitive the first time through, but it's fun!
回答4:
Off the top of my head but I'm sure with some more research there's a more elegant way
File.open( filename ).each_line.to_a[1..-1].each{ |line|... }
Okay scratch that... did a bit of research and this might be better
File.open( filename ).each_line.with_index.drop_while{ |line,index| index == 0 }.each{ |line, index| ... }
回答5:
I doubt that this is idiomatic, but it's simple.
f = File.open(filename)
f.readline
f.each_line do |x|
#...
end
回答6:
I think you are right on track with the Enumerator and drop(1). For some odd reason, while Enumerable defines #drop, Enumerator does not. Here is a working 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
来源:https://stackoverflow.com/questions/2200014/ruby-is-there-something-like-enumerabledrop-that-returns-an-enumerator-instead