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 集合中的元素进行分组,非常有用,而且没有容器操作等动态内存分配,不可能再快了。

posted on 2017-04-03 02:24  李屠户  阅读(230)  评论(0编辑  收藏  举报