返回Enumerable的Ruby Enumerable.collect的等价物?

时间:2010-02-24 16:52:37

标签: ruby enumerable

在这段代码中,我创建了一个字符串“1”到“10000”的数组:

array_of_strings = (1..10000).collect {|i| String(i)}

Ruby Core API是否提供了一种获取可枚举对象的方法,该对象允许我在同一列表中进行枚举,根据需要生成字符串值,而不是生成字符串数组?

这是另一个例子,希望澄清我想要做的事情:

def find_me_an_awesome_username
  awesome_names = (1..1000000).xform {|i| "hacker_" + String(i) }
  awesome_names.find {|n| not stackoverflow.userexists(n) }
end

xform是我正在寻找的方法。 awesome_names是一个Enumerable,因此xform不会创建一个100万字符串的字符串数组,而只是根据需要生成和返回“hacker_ [N]”形式的字符串。

顺便说一句,这就是C#中的样子:

var awesomeNames = from i in Range(1, 1000000) select "hacker_" + i;
var name = awesomeNames.First((n) => !stackoverflow.UserExists(n));

(一种解决方案)

以下是Enumerator的扩展,它添加了一个xform方法。它返回另一个枚举器,它迭代原始枚举器的值,并应用了一个变换。

class Enumerator
  def xform(&block)
    Enumerator.new do |yielder|
      self.each do |val|
        yielder.yield block.call(val)
      end
    end
  end
end

# this prints out even numbers from 2 to 10:
(1..10).each.xform {|i| i*2}.each {|i| puts i}

4 个答案:

答案 0 :(得分:6)

Ruby 2.0引入了Enumerable#lazy,允许其链接mapselect等等,并且只在最后使用to_a生成最终结果,{ {1}}等等......您可以在任何带有first的Ruby版本中使用它。

require 'backports/2.0.0/enumerable/lazy'

否则,您可以使用require 'backports/2.0.0/enumerable/lazy' names = (1..Float::INFINITY).lazy.map{|i| "hacker_" + String(i) } names.first # => 'hacker_1' 。它是Ruby 1.9中的新功能,所以Enumerator.new { with_a_block }如果你需要它在Ruby 1.8.x中。

根据您的示例,以下内容不会创建中间数组,只会构造所需的字符串:

require 'backports/1.9.1/enumerator/new'

如果需要,您甚至可以将100000替换为1.0 / 0(即无穷大)。

要回答您的评论,如果您始终将您的值一对一映射,则可以使用以下内容:

require 'backports/1.9.1/enumerator/new'

def find_me_an_awesome_username
  awesome_names = Enumerator.new do |y|
    (1..1000000).each {|i| y.yield "hacker_" + String(i) }
  end
  awesome_names.find {|n| not stackoverflow.userexists(n) }
end

答案 1 :(得分:1)

听起来你想要一个Enumerator对象,但不完全是。

也就是说,Enumerator对象是一个可用于按需调用next的对象(而不是执行整个循环的each)。 (许多人使用内部迭代器与外部迭代器的语言:each是内部的,而枚举器是外部的。你可以驱动它。)

以下是枚举器的外观:

awesome_names = Enumerator.new do |y|
  number = 1
  loop do
    y.yield number
    number += 1
  end
end

puts awesome_names.next
puts awesome_names.next
puts awesome_names.next
puts awesome_names.next

这是一个链接,更多讨论如何在Ruby中懒惰地使用枚举器:http://www.michaelharrison.ws/weblog/?p=163

在Pickaxe的书中也有一节(Dave Thomas的 Programming Ruby )。

答案 2 :(得分:1)

class T < Range
  def each
    super { |i| yield String(i) }
  end
end

T.new(1,3).each { |s| p s }
$ ruby rsc.rb
"1"
"2"
"3"

接下来要做的是在没有块的情况下调用时返回一个Enumerator ...

答案 3 :(得分:0)

列表包含每种方法:

(1..100000).each