`
simohayha
  • 浏览: 1400891 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

ruby1.9中的Iterators

    博客分类:
  • ruby
阅读更多
在ruby1.9中增加了External Iterators这中新的迭代类型,所有的Enumerable 都是External Iterators.而在ruby1.9之前的版本中的迭代都是internal iterator。

何为external iterator呢,其实我认为也就是一个生成器了:

iterator = 9.downto(1)             # An enumerator as external iterator
begin                              # So we can use rescue below
  print iterator.next while true   # Call the next method repeatedly
rescue StopIteration               # When there are no more values
  puts "...blastoff!"              # An expected, nonexceptional condition
end




这里的Kernel.loop方法就是为了迭代External Iterators而专门创建的。当next方法到最后一个元素的时候,就会抛出StopIteration,因此这里我们捕捉这个异常来判断迭代是否结束.

任何External Iterators都可以调用rewind 方法来重启这个迭代器。要注意如果一个enumerator 基于像File这样的对象,那么调用rewind将不会起作用。

一旦一个External Iterators开始迭代,那么他就不能被clone和duplicated。

我们可以简单的使用External Iterators来创建一个each方法,也就是通过External Iterator来创建一个internal iterator:

module Iterable
  include Enumerable          # Define iterators on top of each
  def each                    # And define each on top of next
    loop { yield self.next }
  end
end


下面我们可以这样做:

def iterate(iterator)
  loop { yield iterator.next }
end

iterate(9.downto(1)) {|x| print x }



下面是三个函数,功能都是一样的,第一个使用internal iterators,第二个虽然使用了External iterators ,可是没有用loop方法,因此代码很丑陋,第三个方法是最好的方法。:

# Call the each method of each collection in turn.
# This is not a parallel iteration and does not require enumerators.
def sequence(*enumerables, &block)
  enumerables.each do |enumerable|
    enumerable.each(&block)
  end
end

# Iterate the specified collections, interleaving their elements.
# This can't be done efficiently without external iterators.
# Note the use of the uncommon else clause in begin/rescue.
def interleave(*enumerables)
  # Convert enumerable collections to an array of enumerators.
  enumerators = enumerables.map {|e| e.to_enum }
  # Loop until we don't have any more enumerators.
  until enumerators.empty?
    begin
      e = enumerators.shift   # Take the first enumerator
      yield e.next            # Get its next and pass to the block
    rescue StopIteration      # If no more elements, do nothing
    else                      # If no exception occurred
      enumerators << e        # Put the enumerator back
    end
  end
end

# Iterate the specified collections, yielding tuples of values,
# one value from each of the collections. See also Enumerable.zip.
def bundle(*enumerables)
  enumerators = enumerables.map {|e| e.to_enum }
  loop { yield enumerators.map {|e| e.next} }
end

# Examples of how these iterator methods work
a,b,c = [1,2,3], 4..6, 'a'..'e'
sequence(a,b,c) {|x| print x}   # prints "123456abcde"
interleave(a,b,c) {|x| print x} # prints "14a25b36cde"
bundle(a,b,c) {|x| print x}     # '[1, 4, "a"][2, 5, "b"][3, 6, "c"]'


这里要注意,在ruby1.8中的zip效率很低,那是因为它首先转换参数为数组,然后迭代他,可是在1.9中,由于我们有了External Iterators,因此它的实现就是直接迭代。因此他就更高效.








8
6
分享到:
评论
1 楼 dennis_zane 2008-03-07  
还是内部迭代器看起来比较自然

相关推荐

Global site tag (gtag.js) - Google Analytics