Stackoverflow 珠玑:用于分组的 LINQ 扩展方法
从 stackoverflow.com 上抄来的,将 IEnumerable 中的元素进行切分的方法,无动态内存分配,地球上最快的实现:
1 public static class LinqExtensions 2 { 3 /// <summary> 4 /// 将 source 中的条目按照 partitionSize 指定的每组数量进行分组 5 /// http://stackoverflow.com/questions/3773403/linq-partition-list-into-lists-of-8-members 6 /// </summary> 7 /// <typeparam name="T"></typeparam> 8 /// <param name="source"></param> 9 /// <param name="partitionSize"></param> 10 /// <returns></returns> 11 public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> source, int partitionSize) 12 { 13 if (partitionSize <= 0) 14 { 15 throw new ArgumentOutOfRangeException(nameof(partitionSize)); 16 } 17 18 int innerListCounter = 0; 19 int numberOfPackets = 0; 20 foreach (var item in source) 21 { 22 innerListCounter++; 23 if (innerListCounter == partitionSize) 24 { 25 yield return source.Skip(numberOfPackets * partitionSize).Take(partitionSize); 26 innerListCounter = 0; 27 numberOfPackets++; 28 } 29 } 30 31 if (innerListCounter > 0) 32 { 33 yield return source.Skip(numberOfPackets * partitionSize); 34 } 35 } 36 37 38 /// <summary> 39 /// 将 source 中的条目按照 numberOfChunks 参数指定的分组数进行切分 40 /// http://stackoverflow.com/questions/438188/split-a-collection-into-n-parts-with-linq/13744322#13744322 41 /// </summary> 42 /// <typeparam name="T"></typeparam> 43 /// <param name="source"></param> 44 /// <param name="numberOfChunks"></param> 45 /// <returns></returns> 46 public static IEnumerable<IEnumerable<T>> Split<T>(this ICollection<T> source, int numberOfChunks) 47 { 48 if (numberOfChunks <= 0 || numberOfChunks > source.Count) 49 { 50 throw new ArgumentOutOfRangeException(nameof(numberOfChunks)); 51 } 52 53 int sizePerPacket = source.Count / numberOfChunks; 54 int extra = source.Count % numberOfChunks; 55 56 for (int i = 0; i < numberOfChunks - extra; i++) 57 { 58 yield return source.Skip(i * sizePerPacket).Take(sizePerPacket); 59 } 60 61 int alreadyReturnedCount = (numberOfChunks - extra) * sizePerPacket; 62 int toReturnCount = extra == 0 ? 0 : (source.Count - numberOfChunks) / extra + 1; 63 for (int i = 0; i < extra; i++) 64 { 65 yield return source.Skip(alreadyReturnedCount + i * toReturnCount).Take(toReturnCount); 66 } 67 } 68 69 70 }
两个方法以不同的形式对 IEnumerable 集合中的元素进行分组,非常有用,而且没有容器操作等动态内存分配,不可能再快了。