来源:Stackoverflow NET技术问答 https://mp.weixin.qq.com/s/Z9O0BmamvVAw6Lu_6Yx_dw 咨询区请问是否可以用 linq 按序生成带有多个固定 size 的块?我的理想情况下还可以对这些 块 进行操作。 回答区说实话,你不需要写任何代码,使用 MoreLINQ 中的批次方法即可,它可以按序拆解到固定大小的桶中,你可以直接在 Nuget 上安装 MoreLINQ 包。 int size = 10; var batches = sequence.Batch(size);
如果你好奇它的实现方法,可参考如下源码: public static IEnumerable<IEnumerable<TSource>> Batch<TSource>( this IEnumerable<TSource> source, int size) { TSource[] bucket = null; var count = 0;
foreach (var item in source) { if (bucket == null) bucket = new TSource[size];
bucket[count++] = item; if (count != size) continue;
yield return bucket;
bucket = null; count = 0; }
if (bucket != null && count > 0) yield return bucket.Take(count).ToArray(); }
这个需求确实比较常见,在 .NET6 中添加了一个 Enumerable.Chunk() 扩展方法,然后你就可以像下面这样使用。 var list = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
var chunks = list.Chunk(3); // returns { { 1, 2, 3 }, { 4, 5, 6 }, { 7 } }
如果你对源码感兴趣,可以参考如下: public static IEnumerable<TSource[]> Chunk<TSource>(this IEnumerable<TSource> source, int size) { if (source == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (size < 1) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.size); } return ChunkIterator(source, size); }
private static IEnumerable<TSource[]> ChunkIterator<TSource>(IEnumerable<TSource> source, int size) { using IEnumerator<TSource> e = source.GetEnumerator(); while (e.MoveNext()) { TSource[] array = new TSource[size]; array[0] = e.Current; int i; for (i = 1; i < array.Length; i++) { if (!e.MoveNext()) { break; } array[i] = e.Current; } if (i == array.Length) { yield return array; continue; } Array.Resize(ref array, i); yield return array; break; } }
点评区发现 .NET6 下的 Enumerable 增加了一些 By 系列方法:MinBy,ExceptBy,IntersectBy,又有得学了。 |