public IEnumerable<T> GetItems<T>() { for (int i=0; i<10000000; i++) { yield return i; } }
这将返回一个包含1000万个整数的可枚举序列,而无需在该长度的内存中分配集合.
有没有办法在Ruby中做同等的事情?我想要处理的具体示例是将矩形数组展平为要枚举的值序列.返回值不必是数组或集合,而是某种只能按顺序迭代/枚举的序列,而不是索引.因此,不需要在存储器中同时分配整个序列.在.NET中,这是IEnumerable和IEnumerable< T>.
由于我更熟悉.NET术语,因此在Ruby世界中使用的术语的任何澄清都会有所帮助.
编辑
也许我原来的问题还不够清楚 – 我认为在C#和Ruby中,yield的含义差别很大,这就引起了混乱.
我不想要一个需要我的方法来使用块的解决方案.我想要一个具有实际返回值的解决方案.返回值允许方便地处理序列(过滤,投影,连接,压缩等).
这是一个如何使用get_items的简单示例:
things = obj.get_items.select { |i| !i.thing.nil? }.map { |i| i.thing }
在C#中,任何返回使用yield返回的IEnumerable的方法都会导致编译器在幕后生成满足此行为的有限状态机.我怀疑使用Ruby的延续可以实现类似的东西,但我还没有看到一个例子,我自己也不清楚如何做到这一点.
我确实可能会使用Enumerable
来实现这一目标.一个简单的解决方案是给我们一个Array(包括模块Enumerable),但我不想在内存中创建一个包含N个项目的中间集合,因为它可以只是懒得提供它们并且完全避免任何内存峰值.
如果这仍然没有意义,那么请考虑上面的代码示例. get_items返回一个枚举,在该枚举上调用select.传递给select的是一个知道如何在需要时提供序列中的下一个项目的实例.重要的是,尚未计算整个项目集.只有当select需要一个项目时它才会要求它,并且get_items中的潜在代码将开始行动并提供它.这种懒惰带有链,使得当地图要求时,select仅从序列中绘制下一个项目.这样,可以一次对一个数据项执行长链操作.实际上,以这种方式构造的代码甚至可以处理无限的值序列而不会出现任何类型的内存错误.
所以,这种懒惰很容易在C#中编码,我不知道如何在Ruby中编写它.
我希望更清楚(我将尽力避免将来在凌晨3点写问题.)
解决方法
Enumerator
(后端移植到1.8.7).见
Generator: Ruby.
陈词滥调的例子:
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() }