【问题标题】:What's the Ruby equivalent of Python `itertools.chain`?Python `itertools.chain` 的 Ruby 等价物是什么?
【发布时间】:2015-01-13 10:14:14
【问题描述】:

Python 的 itertools 模块在使用生成器处理可迭代/迭代器方面提供了很多好处。 Python itertools.chain 的 Ruby 等价物是什么?

【问题讨论】:

  • 您可能想解释一下 itertools.chain 的作用 - 并非每个 Ruby 专家都了解 Python。
  • @FrankSchmitt 它生成一个迭代器,该迭代器顺序链接两个或多个现有迭代器,即从一个迭代器生成值直到其耗尽,然后从另一个迭代器生成值,依此类推。

标签: ruby


【解决方案1】:

我不是 Ruby 程序员,但我认为应该这样做:

def chain(*iterables)
   for it in iterables
       if it.instance_of? String
           it.split("").each do |i|
               yield i
           end
       else
           for elem in it
               yield elem
           end
       end
   end
end

chain([1, 2, 3], [4, 5, 6, [7, 8, 9]], 'abc') do |x|
    print x
    puts
end

输出:

1
2
3
4
5
6
[7, 8, 9]
a
b
c

如果您不想展平字符串,则使用 Array#flatten 可以将其缩短为:

def chain(*iterables)
    return iterables.flatten(1) # not an iterator though
end
print chain([1, 2, 3], [4, 5, 6, [7, 8, 9]], 'abc')
#[1, 2, 3, 4, 5, 6, [7, 8, 9], "abc"]

【讨论】:

    【解决方案2】:

    Python 迭代器的 Ruby 等效项是 Enumerator。没有办法链接两个Enumerators,但可以很容易地写成这样:

    class Enumerator
      def chain(*others)
        self.class.new do |y|
          [clone, *others.map(&:clone)].each do |e|
            loop do y << e.next end
          end
        end
      end
    
      def +(other)
        chain(other)
      end
    end
    
    e1 = %w[one two].each
    e2 = %w[three four].each
    e3 = %w[five six].each
    
    e = e1.chain(e2, e3)
    
    e.map(&:upcase)
    # => ['ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX']
    

    【讨论】:

      【解决方案3】:

      来自Python docs for itertools.chain

      创建一个迭代器,从第一个可迭代对象中返回元素,直到 它被耗尽,然后继续下一个迭代,直到所有的 可迭代对象已用尽。用于将连续序列视为 单序列。

      首先,Python中的一个例子

      from itertools import chain
      
      # nested arrays
      iterables = [
                      ["one", "two"], 
                      ["three", "four"], 
                      ["five", "six", "6", ["eight", "nine", "ten"]]
                  ]
      
      list(chain(*iterables))
      

      输出:

      ['one', 'two', 'three', 'four', 'five', 'six', '6', ['eight', 'nine', 'ten']]
      

      我正在学习 Ruby,因此我尝试使用 Python 文档中的代码示例来复制该行为:

      # taken from Python docs as a guide
      def chain(*iterables):
          # chain('ABC', 'DEF') --> A B C D E F
          for it in iterables:
              for element in it:
                  yield element  # NOTE! `yield` in Python is not `yield` in Ruby. 
                  # for simplicity's sake think of this `yield` as `return`
      

      我的 Ruby 代码:

      def chain(*iterables)
        items = []
        iterables.each do |it|
          it.each do |item|
            items << item
           end
        end
        items
      end
      
      nested_iterables = [%w[one two], %w[three four], %W[five six #{3 * 2}]]
      nested_iterables[2].insert(-1, %w[eight nine ten])
      
      puts chain(*nested_iterables)  
      
      # and to enumerate
      chain(*nested_iterables).each do |it|
        puts it
      end
      

      两个输出:

      ["one", "two", "three", "four", "five", "six", "6", ["eight", "nine", "ten"]]
      

      【讨论】:

        【解决方案4】:

        代码

        def chain(*aaa)
          aaa.each { |aa| (aa.class == String ? aa.split(//) : aa).each { |a| yield a } }
        end
        

        例子

        chain([0, 1], (2..3), [[4, 5]], {6 => 7, 8 => 9}, 'abc') { |e| print e, ',' }
        

        输出

        0,1,2,3,[4, 5],[6, 7],[8, 9],a,b,c,
        

        【讨论】:

          【解决方案5】:

          因为 Ruby 2.6 枚举有一个chain 方法。它不会将字符串拆分为字符。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-11-14
            • 2011-04-12
            • 1970-01-01
            • 1970-01-01
            • 2014-12-29
            • 2011-05-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多