假设我有100个元素的集合。常规枚举器将迭代这100个元素。
我想创建枚举器(它基于常规枚举器,即它不是每个集合,而是一个,一般方法),范围从“hehe”到“there” - 我可以拥有例如,仅在中间迭代20多个元素。
void foo(IEnumerable<int> coll)
{
var regular_iter = coll.GetEnumerator();
regular_iter.MoveNext();
regular_iter.MoveNext();
// ... 8 more
var scoped_iter = new ScopeEnumerator(regular_iterator,20);
所以在这种情况下,当我调用“scoped_iter.Reset()”时,它会被重置为0元素(整个集合的第10个元素)。
而且它“只看到”10-30的元素。
问题是 - 如何实现这样的枚举器?
我需要来自“here”的迭代器,而不是“那里”,因为进入“那里”可能非常耗时。然而,这实际上是次要的,最有问题的是重置方法。
Jon询问了背景。我真正想要实现的是切片集合(即你有 - 比方说 - 10个字符串的集合,但你想把它解释为5个元素的集合,每个元素是2个字符串的集合)。朴素算法非常简单,但效率也很低。收集~16MB(字符串列表)我虽然有另一种方法 - 只需重新解释数据,而不复制它。所以我会创建一个迭代器来从整个集合中选择每个SIZE_OF_SLICE元素,并且我也会创建这个作用域迭代器,它将从第一个迭代器开始并转到SIZE_OF_SLICE元素。
这样就可以重新使用数据,唯一的区别就是你如何迭代数据。切片就足够了,应该很快。
我为IList实现了有效的切片(一旦你假设你有索引器,它就是小菜一碟)但它让我感到不安,你不能(?)为列表(LinkedList)和数组(List)提供通用的高效算法。因此,如果您正在阅读本文并了解如何操作,请不要犹豫,即使在10年之后(假设C#仍然在我们身边),我也不要犹豫不决。
答案 0 :(得分:2)
要获得仅看到元素10-30的迭代器,请使用original.Skip(10).Take(20)
,尽管我认为您不能使用Reset
。
如果您需要重置它,只需使用类似
的内容即可original.Skip(10).Take(20).ToArray()
答案 1 :(得分:2)
为了尽量减少工作量,您基本上使用迭代器填充 支持Reset
(例如List<T>
)的集合,然后返回
执行 lazily 稍微麻烦一点 - 即第一次迭代时,填充一个集合。首次重置后,进入“重播”模式。我确信它是可行的 - 它只是有点棘手。
如果你不得不支持仅在(比方说)15个元素之后第一次重置,那么当你第二次击中第16个元素时,回到原始迭代器就更难了。让人惊讶。
如果你可以确切地确定你的要求,那么实施它可能是一件有趣的事情......
编辑:只是将一些注释放到这个答案中:你不能在没有复制数据的情况下执行一般,因为不能保证迭代器完全支持重置。想象一下,如果迭代器提供来自某个随机数生成器的数据,或者它是一个未被记录的直播 - 显然是为了重放数据,某些东西必须复制它。
如果你有一个特定的源代码实现,那可能会有所不同 - 但你不能通过 IEnumerator<T>
接口来实现。< / p>