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

将多个枚举数转换为一个

  •  3
  • Schwern  · 技术社区  · 6 年前

    class Enumerables
      include Enumerable
    
      def initialize
        @enums = []
      end
    
      def <<(enum)
        @enums << enum
      end
    
      def each(&block)
        if block_given?
          @enums.each { |enum|
            puts "Enumerating #{enum}"
            enum.each(&block)
          }
        else
          to_enum(:each)
        end
      end
    end
    
    enums = Enumerables.new
    enums << 1.upto(3)
    enums << 5.upto(8)
    enums.each { |s| puts s }
    

    举个简单的例子,它需要能够接受这样的无限枚举数。

    inf = Enumerator.new { |y| a = 1; loop { y << a; a +=1 } };
    
    3 回复  |  直到 6 年前
        1
  •  2
  •   Aleksei Matiushkin    6 年前

    毕竟。使用 Enumerable::Lazy#flat_map 具有 .each.lazy

    inf = Enumerator.new { |y| a = 1; loop { y << a; a += 1 } }
    [(1..3).to_a, inf].lazy.flat_map { |e| e.each.lazy }.take(10).force
    #⇒ [1, 2, 3, 1, 2, 3, 4, 5, 6, 7]
    
        2
  •  4
  •   Aleksei Matiushkin    6 年前

    好吧,可以用标准库 Enumerator . 这种方法的优点是它返回 真实的

    MULTI_ENUM = lambda do |*input|
      # dup is needed here to prevent
      #  a mutation of inputs when given
      #  as a splatted param
      # (due to `input.shift` below)
      input = input.dup.map(&:to_enum)
      Enumerator.new do |yielder|
        loop do
          # check if the `next` is presented
          #  and mutate the input swiping out
          #  the first (already iterated) elem
          input.first.peek rescue input.shift
          # stop iteration if there is no input left
          raise StopIteration if input.empty?
          # extract the next element from 
          #  the currently iterated enum and
          #  append it to our new Enumerator
          yielder << input.first.next
        end
      end
    end
    
    MULTI_ENUM.(1..3, 4.upto(5), [6, 7]).
      map { |e| e ** 2 }
    
    #⇒ [1, 4, 9, 16, 25, 36, 49]
    
        3
  •  0
  •   iGian    6 年前

    我最终得到了这个解决方案,也许接近你已经尝试过的:

    def enumerate(*enum)
      enum.each_with_object([]) { |e, arr| arr << e.to_a }.flatten
    end
    
    enumerate( 1..3, 5.upto(8), 3.times, 'a'..'c' ).each { |e| p e }
    
    # => 1, 2, 3, 5, 6, 7, 8, 0, 1, 2, "a", "b", "c"
    

    def enumerate(*enum)
      enum.flat_map { |e| e.to_a }
    end