我有一个元素序列。这个序列只能迭代一次,并且可以是“无限的”。
什么是最好的方法得到这样一个序列的头部和尾部?
更新:如果我在最初的问题中包括一些澄清,那就更好了:)
- 头是序列的第一个元素,尾是“其余的”。这意味着尾也是“无限的”。
- 当我说“无限”时,我的意思是“非常大”,“我不想一次把它全部存储在内存中”。它也可能是真正的无限,比如传感器数据(但我的情况不是这样)。
- 当我说它只能迭代一次时,我的意思是生成序列是资源密集型的,所以我不想再做一次。它也可能是易失性数据,就像传感器数据一样,在下一次读取时不会是相同的(但在我的情况下不是这样)。
5条答案
按热度按时间ttcibm8c1#
将
IEnumerable<T>
分解成head & tail并不适合递归处理(不像函数列表),因为当你递归地使用 tail 操作时,你会创建很多间接寻址。我忽略了像参数检查和异常处理这样的东西,但它表明了这样的想法...
HeadAndTail
方法获取第一个元素,并将其作为元组的第一个元素返回。元组的第二个元素是IEnumerable<T>
,它是由其余元素生成的(通过迭代我们已经创建的枚举器的其余部分)。4c8rllxm2#
Obviously, each call to HeadAndTail should enumerate the sequence again (unless there is some sort of caching used). For example, consider the following:
For the same reason, HeadAndTail could not be implemented as separate Head and Tail methods (unless you want even the first call to Tail to enumerate the sequence again even if it was already enumerated by a call to Head).
Additionally, HeadAndTail should not return an instance of IEnumerable (as it could be enumerated multiple times).
This leaves us with the only option: HeadAndTail should return IEnumerator, and, to make things more obvious, it should accept IEnumerator as well (we're just moving an invocation of GetEnumerator from inside the HeadAndTail to the outside, to emphasize it is of one-time use only).
Now that we have worked out the requirements, the implementation is pretty straightforward:
And now it can be used like this:
Or in recursive functions like this:
gkn4icbw3#
虽然这里的其他方法建议使用
yield return
作为tail
可枚举对象,但这样的方法增加了不必要的嵌套开销。更好的方法是将Enumerator<T>
转换回可以与foreach
一起使用的对象:如果对泛型
IEnumerable<T>
和非泛型IEnumerable
使用单独的WrappedEnumerator
结构,则可以让它们分别实现IEnumerable<T>
和IEnumerable
;但是,它们不会真正遵守IEnumerable<T>
协定,该协定规定应该可以多次调用GetEnumerator()
,每次调用都返回一个独立的枚举数。另一个重要的警告是,如果在
IEnumerator<T>
上使用AsForEach
,则结果WrappedEnumerator
应该被枚举 * 恰好 * 一次。如果它从未被枚举,则底层IEnumerator<T>
将永远不会调用它的Dispose
方法。将上面提供的方法应用于当前的问题,可以很容易地在
IEnumerable<T>
上调用GetEnumerator()
,读出前几项,然后使用AsForEach()
转换余数,以便它可以用于ForEach
循环(或者,如上所述,将其转换为IEnumerable<T>
的实现)。调用GetEnumerator()
创建了对Dispose
的义务,得到了IEnumerator<T>
,并且如果没有任何东西在尾部调用GetEnumerator()
,则执行头/尾分离的类将没有办法做到这一点。093gszye4#
这可能不是最好的方法,但如果使用
.ToList()
方法,则可以获得[0]
和[Count-1]
位置的元素,如果Count〉0。但是您应该指定“* 只能迭代一次 *”是什么意思
wbgh16ku5#
.First()
和.Last()
到底有什么问题?虽然是的,我不得不同意那些问“无限列表的尾部是什么意思”的人...这个概念没有意义,IMO。