LINQ/IEnumerable Skip().Take()效率与"yield return"一起使用

use*_*317 4 c# linq performance enumerable

我有一个关于效率Skip()Take()使用时间的问题IEnumerable<>.

我正在返回我的所有数据列表,IEnumerable<>并使用'yield return'来防止我必须分配大量内存来传回数据.这非常有效.

但是,稍后在我的过程中,我想批量处理这些数据,并一次从我的列表中删除20个条目.我心想啊..啊!这非常适合普查员.

我发现非常有用Skip(),并Take()在方法IEnumerable interface不过我现在意识到这导致我的循环每次重新interate从此开始.

从一个页面分页数据的最佳方法是IEnumerable什么?我最好不要使用MoveFirst()和使用MoveNext()枚举器而不是Skip()Take()

我做了一些谷歌搜索,但找不到答案..

有人可以帮忙吗?

我真的很喜欢LINQ功能,IEnumerable<>但我必须考虑效率.

Ser*_*rvy 6

您可以编写一个Batch方法将一系列项目转换为给定大小的批处理序列,这可以在不需要多次迭代源序列的情况下完成,并且可以将内存占用限制为仅保持一个批处理的大小在记忆中:

public static IEnumerable<IEnumerable<T>> Batch<T>(
    this IEnumerable<T> source, int batchSize)
{
    List<T> buffer = new List<T>(batchSize);

    foreach (T item in source)
    {
        buffer.Add(item);

        if (buffer.Count >= batchSize)
        {
            yield return buffer;
            buffer = new List<T>(batchSize);
        }
    }
    if (buffer.Count > 0)
    {
        yield return buffer;
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*age 0

内存和 CPU 之间总是需要进行权衡。目前,您通过向前移动直到页面开始来获取页面的项目Skip,并且项目将由每个页面请求上的迭代器块重新计算。

但是,您可以通过缓存到目前为止计算的项目来避免重新计算,但这将使用一些内存。您声明您决定使用迭代器块来避免使用过多内存,但也许仅缓存必要项目的“智能”解决方案可能有用?

在堆栈溢出问题的答案中,是否有一个 IEnumerable 实现仅迭代其源(例如 LINQ),一旦您会发现一些解决方案仅计算和存储足够的元素以便能够移动到您的页面。例如,如果您的页面大小为 10,而您想要第 5 页,则您将仅计算并存储前 60 个项目。对第 3 页的后续请求将使用已计算的项目,而对第 10 页的请求将计算并缓存足够的项目以获取该页面的数据。

如果您想执行分页而不从第一个元素开始,也不想不必要地存储未使用的项目,则需要某种方法在特定页面重新启动迭代,而不必迭代所有先前的元素。IEnumerable<T>并且IEnumerator<T>没有提供足够的功能来做到这一点。