计数和foreach产生不同的结果

问题描述 投票:1回答:1

我一直在用一种方法把集合分成几批形成这个答案--。https:/stackoverflow.coma175988781012739。:

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size) {
    using (IEnumerator<T> enumerator = source.GetEnumerator())
        while (enumerator.MoveNext())
            yield return TakeIEnumerator(enumerator, size);
}

private static IEnumerable<T> TakeIEnumerator<T>(IEnumerator<T> source, int size) {
    int i = 0;
    do yield return source.Current;
    while (++i < size && source.MoveNext());
}

迭代处理以下结果时 Batch<T> 会得到预期的收藏数量,但当调用 CountToList 报道了外链长度。

var collection = new int[10];
var count = 0;
foreach(var batch in collection.Batch(2))
    ++count;
Assert.AreEqual(5, count); // Passes
// But
Assert.AreEqual(5, collection.Batch(2).Count());        // Fails
Assert.AreEqual(5, collection.Batch(2).ToList().Count); // Fails

这是怎么做到的,有办法解决吗?

c# linq
1个回答
3
投票

您的 TakeIEnumerator<T> 方法取决于枚举器的位置(source),因此,它本身......是依赖于时间的。如果结果是通过先整理 "外部 "结果来迭代的,即

var batches = source.Batch(24).ToList();
// then iterate in any way

那么根据定义。source 用完了,你会得到N个项目,在 batches,其中 N 是指从 source而所有的批次都会是空的,因为那里有 没有数据了. 然而,如果结果是先迭代深度,即

foreach (var batch in source) {
    foreach (var item in batch) {...}
}

那么你看的就是打开的光标。最终,这种方法本质上是脆弱和危险的。IMO,你的批处理方法应该创建计算数据的缓冲区,也许是个 List<T> 或类似。这将分配,但:会很可靠。例如:

private static IEnumerable<T> TakeIEnumerator<T>(IEnumerator<T> source, int size) {
    var buffer = new List<T>(size);
    int i = 0;
    do buffer.Add(source.Current);
    while (++i < size && source.MoveNext())
    return buffer;
}
© www.soinside.com 2019 - 2024. All rights reserved.