【问题标题】:Clone an Enumerator in Ruby?在 Ruby 中克隆枚举器?
【发布时间】:2012-11-07 11:26:46
【问题描述】:

我有一棵树,我正试图遍历它。在遍历它时,我保留了一堆枚举器,其中每个枚举器用于枚举树的子节点。

我希望能够复制这个枚举器堆栈并将其交给另一个对象,以便它可以从堆栈状态指示的位置开始遍历树。

当我尝试在 Enumerator 上调用 #dup 时,出现错误。是否可以复制枚举器?如果没有,我怎么能完成同样的事情? (我曾考虑将一堆整数作为索引,但担心效率。

这里有一些代码来显示我所看到的......

一旦第一个枚举器启动,就不能复制它。这就是我的情况。

a = [1,2,3].each
 => #<Enumerator: [1, 2, 3]:each> 
a.next
 => 1 
b = a.dup
TypeError: can't copy execution context
    from (irb):3:in `initialize_copy'
    from (irb):3:in `initialize_dup'
    from (irb):3:in `dup'
    from (irb):3

【问题讨论】:

  • 致电@dup?你的意思是打电话给dup
  • 这是一项学术练习还是您会从RubyTree gem 中受益?
  • #next 不是在 ruby​​ 中使用枚举器的首选方式。我相信它是使用纤维定义的,并且堆栈帧不能被复制。你能详细说明你需要这个做什么吗?也许我们可以建议更多的 ruby​​ 方法来解决您的问题。
  • @samuil:#next 是进行外部迭代的首选方式。是的,枚举数可以在迭代之前被复制。
  • 您是否尝试使用分子进行深度优先树遍历?

标签: ruby enumerator


【解决方案1】:

实现您自己的枚举器类。

除了递增内部计数器之外,枚举器并没有什么魔力。

class MyArrayEnumerator
  def initialize(array)
    @ary,@n=array,0
  end
  def next
    raise StopIteration if @n == @ary.length
    a=@ary[@n];@n+=1;a
  end
end

class Array
  def my_each
    MyArrayEnumerator.new(self)
  end
end

a = [1,2,3].my_each # => #<MyArrayEnumerator:0x101c96588 @n=0, @array=[1, 2, 3]>
a.next # => 1
b = a.dup # => #<MyArrayEnumerator:0x101c95ae8 @n=1, @array=[1, 2, 3]>
a.next # => 2
b.next # => 2

【讨论】:

    【解决方案2】:

    改用clone

    e1 = [1,2,3].each
    e1.dup # TypeError: can't copy execution context
    e2 = e1.clone
    e1.next #=> 1
    e2.next #=> 1
    

    【讨论】:

    • 你可以dupclone,只要枚举数是原始的。一旦你开始枚举(例如通过next),它们都会引发 TypeError。
    【解决方案3】:

    在 Enumerator 的实例中保留一个“头”,并为后面的副本存储历史记录:

    class Enum
    
      def initialize()
        @history = [] # history will be shared between instances
        @history_cursor = -1
        @head = Enumerator.new do |yielder|
          @yielder = yielder
          enumerate
        end
      end
    
      def next
        if @history_cursor < @history.count - 1
          @history[@history_cursor += 1]
        else
          new_item @head.next
        end
      end
    
      private
    
      def new_item item
        @history << item
        @history_cursor = @history.count - 1
        item
      end
    
      def enumerate
        13.times do |i|
          @yielder << i # yielder is shared between instances
        end
      end
    
    end
    

    用法:

    enum1 = Enum.new
    p enum1.next # 0
    enum2 = enum1.clone
    p enum2.next # 1
    p enum1.next # 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 2018-05-14
      • 1970-01-01
      • 1970-01-01
      • 2012-02-11
      • 2020-10-19
      相关资源
      最近更新 更多