2010-02-08 60 views
1

所以,我不完全赞同Ruby 1.9在枚举器上的更改,但我希望对集合进行惰性过滤/映射,例如,如何创建一个惰性枚举器将是相当于这...Ruby 1.9列举更改

(1..100).find_all{|x| x % 2 == 1}.map{|x| x * 2}.find_all{|x| x % 3 == 0} 

我试着传递一个lambda到#enum_for,但它不能在我的机器上工作。

回答

3

您可以找到lazy_select和lazy_map in this blog的实现。您将只需通过这两种方法来扩展枚举模块。那么你应该可以使用

(1..100).lazy_select{|x| x % 2 == 1}.lazy_map{|x| x * 2}.lazy_select{|x| x % 3 == 0} 
+0

好的,这看起来比我的解决方案好... – sepp2k 2010-02-08 13:01:08

0

不幸的是,你不能用enum_for做到这一点。你必须使用类似这样的懒惰枚举:

class LazyEnum 
    include Enumerable 

    attr_accessor :enum, :operations 

    def initialize enum 
    @enum = enum 
    @operations = [] 
    end 

    def each 
    enum.each do |x| 
     filtered = false 
     operations.each do |type, op| 
     if type == :filter 
      unless op[x] 
      filtered = true 
      break 
      end 
     else 
      x = op[x] 
     end 
     end 
     yield x unless filtered 
    end 
    end 

    def map! &blk 
    @operations << [:transform, blk] 
    self 
    end 

    def select! &blk 
    @operations << [:filter, blk] 
    self 
    end 

    def reject! 
    select! {|x| !(yield x)} 
    end 

    def dup 
    LazyEnum.new self 
    end 

    def map &blk 
    dup.map! &blk 
    end 

    def select &blk 
    dup.select! &blk 
    end 

    def reject &blk 
    dup.reject! &blk 
    end 
end 

LazyEnum.new(1..100).select{|x| x % 2 == 1}.map{|x| x * 2}.select{|x| x % 3 == 0} 
#=> #<LazyEnum:0x7f7e11582000 @enum=#<LazyEnum:0x7f7e115820a0 @enum=#<LazyEnum:0x7f7e11582140 @enum=#<LazyEnum:0x7f7e115822d0 @enum=1..100, @operations=[]>, @operations=[[:filter, #<Proc:[email protected](irb):348>]]>, @operations=[[:transform, #<Proc:[email protected](irb):348>]]>, @operations=[[:filter, #<Proc:[email protected](irb):348>]]> 
irb(main):349:0> LazyEnum.new(1..100).select{|x| x % 2 == 1}.map{|x| x * 2}.select{|x| x % 3 == 0}.to_a 
#=> [6, 18, 30, 42, 54, 66, 78, 90, 102, 114, 126, 138, 150, 162, 174, 186, 198]