红宝石等效的C#'s‘的产量’关键字,或未经预分配存储器中创建序列

StackOverflow https://stackoverflow.com/questions/2282615

  •  21-09-2019
  •  | 
  •  

在C#中,你可以做这样的事情:

public IEnumerable<T> GetItems<T>()
{
    for (int i=0; i<10000000; i++) {
        yield return i;
    }
}

此返回1000点的整数可枚举序列,而不在该长度的存储器分配过的集合。

有没有在Ruby中做一个等价的东西的一种方式?我想处理的特定示例是矩形阵列的平坦化到值的序列进行枚举。返回值并不一定是ArraySet,而是某种序列,只能进行迭代/列举为了不被索引。因此,整个序列不需要在内存中分配的同时。在.NET,这是IEnumerableIEnumerable<T>

在Ruby世界在这里使用的术语任何澄清将是有益的,因为我更熟悉.NET术语。

修改

也许我原来的问题是不是真的足够清晰的 - 我认为yield在C#中具有非常不同的含义和Ruby是混乱的原因在这里的事实。

我不希望出现这种情况,需要我的方法使用的块中的溶液。我想有一个实际的返回值的解决方案。返回值允许序列(过滤,投影,级联,压缩和解等)的方便的处理。

下面是我如何可能会使用get_items一个简单的例子:

things = obj.get_items.select { |i| !i.thing.nil? }.map { |i| i.thing }

在C#,任何返回一个使用IEnumerable yield return方法导致编译器生成的有限状态机,迎合针对此行为在幕后。我怀疑类似的可以使用Ruby的延续来实现的东西,但我还没有看到一个例子,我不十分清楚自己对如何做到这一点做。

这确实似乎可能的,我可能会使用 Enumerable 来实现这一目标。一个简单的解决方案是我们的Array(包括模块Enumerable),但我不希望在内存中创建与N项中间集合时,它可能只是为他们提供懒洋洋地避免任何内存秒杀一切。

如果这仍然没有意义,再考虑上面的代码示例。 get_items返回一个枚举,据此select被调用。什么是传递给select是一个知道如何序列中提供的下一个项目,只要它是需要一个实例。重要的是,项目的整个集合尚未计算。只有当select需要一个项目将是自讨苦吃,并在get_items潜代码会踢成行动,并提供它。此懒惰沿着链携带,当select要求它使得map只从序列绘制下一个项目。这样,可以在一个数据项在一个时间执行一个长的操作链。实际上,代码结构以这种方式,甚至可以处理的无限无任何种的存储器错误的值的序列。

因此,这种懒惰很容易在C#编码,我不知道如何做到这一点的红宝石。

我希望更清晰(我会尽量避免在凌晨3点在今后的写作问题。)

有帮助吗?

解决方案

它是由 Enumerator 因为红宝石1.9支持(和后移植1.8.7)。请参阅发生器:红宝石

陈词滥调示例:

fib = Enumerator.new do |y|
  y.yield i = 0
  y.yield j = 1
  while true
    k = i + j
    y.yield k
    i = j
    j = k
  end
end

100.times { puts fib.next() }

其他提示

您具体的例子是相当于10000000.times,但让我们假设针对该次方法并不存在的时刻,你想实现它自己,它会是这样的:

class Integer
  def my_times
    return enum_for(:my_times) unless block_given?
    i=0
    while i<self
      yield i
      i += 1
    end
  end
end

10000.my_times # Returns an Enumerable which will let
               # you iterate of the numbers from 0 to 10000 (exclusive)

编辑:澄清我的回答一个位:

在上面的例子中my_times可以是(并)使用没有块,它将返回一个枚举对象,这将让你迭代数目从0到n。因此,它是完全等同于你的例子在C#。

此工作使用enum_for方法。该enum_for方法作为其参数的方法,这将产生一些项目的名称。然后,它返回枚举类的一个实例(它包括了模块可枚举),其中,当遍历将执行给定的方法,给你这是由该方法产生的项目。请注意,如果你只在枚举的第一个X项目迭代,该方法将只(即只之多必要的方法将被执行)执行,直到X项目已产生了,如果你遍历枚举两次,方法将被执行两次。

在1.8.7+它已成为以限定的方法,其产率的物品,这样,当不使用块调用,它们将返回一个枚举这将让在这些项目懒惰地用户迭代。这是通过添加线return enum_for(:name_of_this_method) unless block_given?像我在我的例子一样的方法的开始时进行。

而不必太多红宝石的经验,在yield return做什么C#通常被称为懒评价懒执行:提供只需要他们的答案。这不是分配内存,它是关于直到实际需要推迟计算,表达了类似简单的线性执行(而不是底层的迭代器与国家节能)的方式。

一个快速谷歌处于测试翻起红宝石库。看它是否是你想要的。

C#撕开“成品率”关键字右出Ruby-的看到实施迭代这里更多。

至于你的实际问题,你有可能是一个数组的数组,你想在列表上的完整长度来创建一个单向迭代?也许值得看array.flatten为出发点 - 如果表现正常的话,你可能就不需要去太多的进一步

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top