Ruby:组合枚举器,创建一个新的枚举器

时间:2016-04-05 13:40:07

标签: ruby

我需要一个类似于Array#select的函数,但不仅将数据项传递给块,还传递给元素的索引(类似于Enumerable#each_with_index)。我试过这个:

class Array  
  def select_with_index
    self.each_with_index.select {|*args| yield(*args)}.map(&:first)
  end
end

这似乎确实有效:

['a','b','a','a','c'].select_with_index {|letter,index| letter == 'a' && index > 1 }

结果

["a", "a"]

正如所料。但是,我不喜欢我的解决方案是,提供一个块。可以在没有块的情况下调用Ruby核心中的类似方法,并生成Enumerator。我怎样才能做到这一点?我知道我可以使用block_given?来测试块的存在,但是我该如何继续呢?我需要Fiber吗?

BTW,代码应该适用于Ruby 1.9.3。和2.x。

2 个答案:

答案 0 :(得分:3)

class Array  
  def select_with_index
    #      ⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓  this
    return enum_for(:select_with_index) unless block_given?
    each_with_index.select {|*args| yield(*args)}.map(&:first)
  end
end

答案 1 :(得分:2)

您不需要自己的方法。您可以利用select如果在没有块的情况下调用而返回枚举数这一事实,那么您可以在顶部打一个with_index

p ['a','b','a','a','c'].select.with_index {|letter,index| letter == 'a' && index > 1 }
# >> ["a", "a"]

如果确实希望这是一个数组上的方法(用于动态调用和诸如此类),这是微不足道的:

class Array
  def select_with_index(&block)
    select.with_index(&block)
  end
end

p ['a','b','a','a','c'].select_with_index {|letter,index| letter == 'a' && index > 1 }  
p ['a','b','a','a','c'].select_with_index
# >> ["a", "a"]
# >> #<Enumerator: #<Enumerator: ["a", "b", "a", "a", "c"]:select>:with_index>