1

假设我有 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 中的元素。

问题是——如何实现这样的枚举器?

编辑

1.

我需要来自“这里”的迭代器,而不是来自“那里”的迭代器,因为到达“那里”可能非常耗时。不过这确实是小事,最有问题的是Reset方法。

2.

乔恩询问了背景。我真正尝试实现的是对集合进行切片(即,你有——比如说——10 个字符串的集合,但你想将其解释为 5 个元素的集合,每个元素是 2 个字符串的集合)。朴素算法非常简单,但也非常低效。收集~16MB(字符串列表),我想到了另一种方法——简单地重新解释数据,而不复制它。所以我会创建一个迭代器,它从整个集合中挑选每个 SIZE_OF_SLICE 元素,并且我会创建这个范围内的迭代器,它将从第一个迭代器开始,然后选择 SIZE_OF_SLICE 元素。

这样数据将被重新使用,唯一的区别是你如何迭代它。切片就足够了,而且应该很快。

3

我为 IList 实现了有效的切片(一旦你假设你有索引器,它就是小菜一碟)但它让我感到不安,你不能(?)为列表(LinkedList)和数组(List)提供通用的高效算法。因此,如果您正在阅读本文,并且知道如何去做,请不要犹豫回答,即使 10 年后也是如此(假设 C# 仍将与我们同在)。

4

2 回答 2

2

要以最少的努力做到这一点,您基本上会使用迭代器填充一个支持(例如)的集合然后Reset返回List<T>它。

懒惰地做这件事有点棘手- 即第一次迭代时,填充一个集合。第一次重置后,进入“重播”模式。我确信这是可行的——只是有点棘手。

如果您必须支持在仅(例如)15 个元素之后第一次重置,然后当您第二次遇到第 16 个元素时,返回到原始迭代器,那将更加棘手。哎呀。

如果您可以准确地确定您有什么要求,那么实现它可能是一件有趣的事情......

编辑:只是为了在这个答案中加入一些评论:如果不复制数据,一般情况下你不能这样做,因为不能保证迭代器完全支持被重置。想象一下,如果迭代器正在提供来自某个随机数生成器的数据,或者它是一个没有被记录的直播——显然要重播数据,必须复制它。

如果您考虑到特定的源实现,那可能会有所不同——但您不能通过IEnumerator<T>接口来实现。

于 2011-07-28T05:25:38.940 回答
2

要获得一个只能看到元素 10-30 的迭代器,请使用original.Skip(10).Take(20),尽管我认为您不能使用Reset它。

如果您需要能够重置它,只需使用类似的东西

original.Skip(10).Take(20).ToArray()
于 2011-07-28T05:18:13.143 回答