代码之家  ›  专栏  ›  技术社区  ›  Samuel Danielson

Ruby:是否有类似Enumerable#drop的东西可以返回枚举数而不是数组?

  •  8
  • Samuel Danielson  · 技术社区  · 15 年前

    我有一些固定宽度的大文件,我需要删除标题行。

    跟踪迭代器似乎不是很习惯用法。

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

    Ruby的习惯用法是什么?

    6 回复  |  直到 12 年前
        1
  •  5
  •   Debilski    15 年前

    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
  •  7
  •   glenn jackman    15 年前

    轻微地 整洁:

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

    io = File.open(fname)
    # discard the first line
    io.gets
    # process the rest of the file
    io.each_line {|line| ...}
    io.close
    
        3
  •  2
  •   rampion    15 年前

    既然你已经得到了合理的答案,这里有一个完全不同的处理方法。

    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)
    

    这既不是惯用的,也不是非常直观的第一次通过,但它的乐趣!

        4
  •  1
  •   Farrel    15 年前

    我不知道,但我相信,通过更多的研究,会有一种更优雅的方式

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

    好的,把它擦掉。。。做了一些研究,这可能会更好

    File.open( filename ).each_line.with_index.drop_while{ |line,index|  index == 0 }.each{ |line, index| ... }
    
        5
  •  1
  •   Shadowfirebird    15 年前

    我怀疑这是否惯用,但它很简单。

    f = File.open(filename)
    f.readline
    f.each_line do |x|
       #...
    end
    
        6
  •  1
  •   Bill Burcham    12 年前

    我认为您使用枚举器和drop(1)是正确的。出于某种奇怪的原因,虽然枚举器定义了#drop,但枚举器却没有。这是一个有效的枚举器#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