代码之家  ›  专栏  ›  技术社区  ›  mackenir

相当于返回可枚举的Ruby Enumerable.Collect?

  •  7
  • mackenir  · 技术社区  · 16 年前

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

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

    Ruby核心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 是我正在寻找的方法。 好名字是可以数的,所以 变换 不是创建100万个元素的字符串数组,而是根据需要生成并返回“hacker_uun”形式的字符串。

    顺便说一下,这就是C中的情况:

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

    (一个解决方案)

    这里是添加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 回复  |  直到 16 年前
        1
  •  6
  •   tckmn    12 年前

    引入Ruby 2.0 Enumerable#lazy 它允许一个人用链子 map , select 等等,最后只生成 to_a , 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'
    

    否则,您可以使用 Enumerator.new { with_a_block } . 这是Ruby1.9的新特性,所以 require 'backports/1.9.1/enumerator/new' 如果在Ruby1.8.x中需要它的话。

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

    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.0/0(即无穷大)代替100000。

    要回答您的意见,如果您总是将值一一映射,则可以具有如下内容:

    module Enumerable
      def lazy_each
        Enumerator.new do |yielder|
          each do |value|
            yielder.yield(yield value)
          end
        end
      end
    end
    
    awesome_names = (1..100000).lazy_each{|i| "hacker_#{i}"}
    
        2
  •  1
  •   Telemachus MrJames    16 年前

    听起来您需要一个枚举器对象,但不完全需要。

    也就是说,枚举器对象是可以用来调用的对象 next 按需(而不是 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

    这本鹤嘴锄书上还有一节( Ruby编程 戴夫·托马斯)。

        3
  •  1
  •   DigitalRoss    16 年前
    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"
    

    接下来要做的是在没有块的情况下调用时返回枚举器…

        4
  •  0
  •   ennuikiller    16 年前

    列表有每个方法:

    (1..100000).each
    
    推荐文章