考虑以下代码
IEnumerable<Items> remainingItems = Items
var results = new List<List<Items>>();
var counter = 0;
while (remainingItems.Any())
{
var result = new List<Item>();
result.AddRange(remainingItems.TakeWhile(x => somePredicate(x, counter));
results.Add(result);
remainingItems = remainingItems.Skip(result.Count);
counter++;
}
如果不清楚发生了什么,我将采用 Ienumerable 并迭代它直到谓词失败,将所有这些项目放入一堆,然后继续迭代剩余的项目直到下一个谓词失败,然后将所有这些都在一堆。冲洗、洗涤、重复。
现在我想重点关注的是 Ienumerable.Skip()
由于它使用延迟执行,这意味着我必须在每个循环中遍历我已经跳过的所有元素。
我可以使用 ToList() 来强制它求值,但是它需要遍历所有剩余的项目才能这样做,这同样糟糕。
所以我真正需要的是一个 IEnumerable,它会急切地跳过,并存储我们到达的第一个最后一点,以便从那里继续。所以我需要一些功能,例如:
IEnumerable.SkipAndCache(n)
允许我从第 n 个项目开始访问 IEnumerator。
有什么想法吗?
最佳答案
您可以使用 MoreLinq为了那个原因。有一个名为 Memoize
的实验性函数可以延迟缓存序列。所以代码看起来像这样:
while (remainingItems.Any())
{
var result = new List<Item>();
result.AddRange(remainingItems.TakeWhile(x => somePredicate(x, counter));
results.Add(result);
remainingItems = remainingItems.Skip(result.Count).Memoize();
counter++;
}
这里不会具体化结果,因为还是惰性求值:
remainingItems = remainingItems.Skip(result.Count).Memoize();
这里 remainingItems
序列将被评估和缓存(迭代器不会像 ToList
那样遍历所有元素):
remainingItems.Any()
这里将使用缓存:
result.AddRange(remainingItems.TakeWhile(x => somePredicate(x, counter));
要使用这个方法你需要添加:
using MoreLinq.Experimental;
关于c# - 缓存 LINQ 查询 - IEnumerable.Skip(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51417755/