如何批量循环浏览IEnumerable
我正在开发ac#程序,它有一个“IEnumerable用户”,存储400万用户的ID。 我需要通过Ienummerable循环,每次提取一批1000个ID,以另一种方法执行一些操作。
我如何从Ienumerable的开始一次提取1000个ID …做一些其他事情然后获取下一批1000个等等?
这可能吗?
听起来就像你需要使用你的对象的Skip和Take方法。 例:
users.Skip(1000).Take(1000)
这将跳过前1000,并采取下一个1000.你只需要增加每次调用跳过的金额
您可以使用带跳过参数的整数variables,您可以调整跳过的数量。 然后你可以用一个方法来调用它。
public IEnumerable<user> GetBatch(int pageNumber) { return users.Skip(pageNumber * 1000).Take(1000); }
您可以使用更多的LINQ 批处理方法(可从NuGet获得):
foreach(IEnumerable<User> batch in users.Batch(1000)) // use batch
如果简单使用库不是一个选项,你可以重用实现:
public static IEnumerable<IEnumerable<T>> Batch<T>( this IEnumerable<T> source, int size) { T[] bucket = null; var count = 0; foreach (var item in source) { if (bucket == null) bucket = new T[size]; bucket[count++] = item; if (count != size) continue; yield return bucket.Select(x => x); bucket = null; count = 0; } // Return the last bucket with all remaining elements if (bucket != null && count > 0) yield return bucket.Take(count); }
顺便说一句,你可以简单地返回bucket而不用调用Select(x => x)
。 Select对数组进行了优化,但是对每个项目仍然会调用select器委托。 所以,在你的情况下,最好使用
yield return bucket;
最简单的方法是使用LINQ中的GroupBy
方法:
var batches = myEnumerable .Select((x, i) => new { x, i }) .GroupBy(p => (pi / 1000), (p, i) => px);
但是对于更复杂的解决scheme,请参阅此博客文章 ,了解如何创build自己的扩展方法。 复制在这里为后人:
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> collection, int batchSize) { List<T> nextbatch = new List<T>(batchSize); foreach (T item in collection) { nextbatch.Add(item); if (nextbatch.Count == batchSize) { yield return nextbatch; nextbatch = new List<T>(); // or nextbatch.Clear(); but see Servy's comment below } } if (nextbatch.Count > 0) yield return nextbatch; }
尝试使用这个:
public static IEnumerable<IEnumerable<TSource>> Batch<TSource>( this IEnumerable<TSource> source, int batchSize) { var batch = new List<TSource>(); foreach (var item in source) { batch.Add(item); if (batch.Count == batchSize) { yield return batch; batch = new List<TSource>(); } } if (batch.Any()) yield return batch; }
并使用以上function:
foreach (var list in Users.Batch(1000)) { }
您可以使用Take和Skip Enumerable扩展方法来实现这一点。 有关使用结帐linq 101的更多信息
像这样的东西可以工作:
List<MyClass> batch = new List<MyClass>(); foreach (MyClass item in items) { batch.Add(item); if (batch.Count == 1000) { // Perform operation on batch batch.Clear(); } } // Process last batch if (batch.Any()) { // Perform operation on batch }
你可以把它推广到一个通用的方法,就像这样:
static void PerformBatchedOperation<T>(IEnumerable<T> items, Action<IEnumerable<T>> operation, int batchSize) { List<T> batch = new List<T>(); foreach (T item in items) { batch.Add(item); if (batch.Count == batchSize) { operation(batch); batch.Clear(); } } // Process last batch if (batch.Any()) { operation(batch); } }
您可以使用Take operator linq
链接: http : //msdn.microsoft.com/fr-fr/library/vstudio/bb503062.aspx