将C#集合拆分为相等的部分,保持排序

我正在尝试将一个集合拆分成多个集合,同时保持我对集合的排序。 我尝试使用以下扩展方法,但它错误地打破了它们。 基本上,如果我要查看集合中的项目,与加入的分解集合相比,顺序应该相同。 这是我使用的代码不起作用:

public static IEnumerable<IEnumerable> Split(this IEnumerable list, int parts) { int i = 0; var splits = from name in list group name by i++ % parts into part select part.AsEnumerable(); return splits; } 
  • int parts =子枚举数

我不得不利用这个来比较4个组中的对象列表…它将使对象保持原始所拥有的顺序。 可以扩展为“List”之外的其他内容

 ///  /// Partition a list of elements into a smaller group of elements ///  ///  ///  ///  ///  public static List[] Partition(List list, int totalPartitions) { if (list == null) throw new ArgumentNullException("list"); if (totalPartitions < 1) throw new ArgumentOutOfRangeException("totalPartitions"); List[] partitions = new List[totalPartitions]; int maxSize = (int)Math.Ceiling(list.Count / (double)totalPartitions); int k = 0; for (int i = 0; i < partitions.Length; i++) { partitions[i] = new List(); for (int j = k; j < k + maxSize; j++) { if (j >= list.Count) break; partitions[i].Add(list[j]); } k += maxSize; } return partitions; } 

对于这个相当古老的问题,一个稍微干净的LINQ方法:

 public static IEnumerable> Partition(this IEnumerable source, int n) { var count = source.Count(); return source.Select((x, i) => new { value = x, index = i }) .GroupBy(x => x.index / (int)Math.Ceiling(count / (double)n)) .Select(x => x.Select(z => z.value)); } 

Jon Skeet的MoreLINQ库可能会为您提供帮助:

https://code.google.com/p/morelinq/source/browse/MoreLinq/Batch.cs

 var items = list.Batch(parts); // gives you IEnumerable> var items = list.Batch(parts, seq => seq.ToList()); // gives you IEnumerable> // etc... 

另一个例子:

 public class Program { static void Main(string[] args) { var list = new List(); for (int i = 1; i < 10000; i++) { list.Add(i); } var batched = list.Batch(681); // will print 15. The 15th element has 465 items... Console.WriteLine(batched.Count().ToString()); Console.WriteLine(batched.ElementAt(14).Count().ToString()); Console.WriteLine(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); } } 

当我扫描批次的内容时,保留了排序。

  double partLength = list.Count() / (double)parts; int i = 0; var splits = from name in list group name by Math.Floor((double)(i++ / partLength)) into part select part; 

据我所知,你希望在相同大小的几个部分上打破可枚举,而不会破坏你的元素的顺序。 看起来唯一的选择是首先可以枚举输入的长度,因此在枚举中至少需要两次迭代。

  public static IEnumerable> Split(this IEnumerable list, int parts) { int nGroups = (int)Math.Ceiling(list.Count() / (double)parts); var groups = Enumerable.Range(0, nGroups); return groups.Select(g => list.Skip(g * parts).Take(parts)); } 

这将完全按照要求完成。 它还将迎合不均匀的分组,即10个组中的27个元素将产生7组,每组3组和3组

  public static IEnumerable> SplitMaintainingOrder(this IEnumerable list, int parts) { if (list.Count() == 0) return Enumerable.Empty>(); var toreturn = new List>(); var splitFactor = Decimal.Divide((decimal)list.Count(), parts); int currentIndex = 0; for (var i = 0; i < parts; i++) { var toTake = Convert.ToInt32( i == 0 ? Math.Ceiling(splitFactor) : ( (Decimal.Compare(Decimal.Divide(Convert.ToDecimal(currentIndex), Convert.ToDecimal(i)), splitFactor) > 0) ? Math.Floor(splitFactor) : Math.Ceiling(splitFactor))); toreturn.Add(list.Skip(currentIndex).Take(toTake)); currentIndex += toTake; } return toreturn; } 

用于演示目的

  [TestMethod] public void splitlist() { var list = new decimal[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }; var splitlists = list.SplitMaintainingOrder(10); int i = 1; foreach (var group in splitlists) { Console.WriteLine("Group {0} elements {1}", i++, String.Join(",", group)); } } 

上面的演示产生了

 Test Name: splitlist Test Outcome: Passed Result StandardOutput: Group 1 elements 1,2,3 Group 2 elements 4,5 Group 3 elements 6,7,8 Group 4 elements 9,10,11 Group 5 elements 12,13 Group 6 elements 14,15,16 Group 7 elements 17,18,19 Group 8 elements 20,21 Group 9 elements 22,23,24 Group 10 elements 25,26,27 

要将通用列表拆分为相等的块,请使用以下generics方法

  private IEnumerable> SplitMaintainingOrder(IEnumerable list, int columnCount) { var elementsCount = list.Count(); int rowCount = elementsCount / columnCount; int noOfCells = elementsCount % columnCount; int finalRowCount = rowCount; if (noOfCells > 0) { finalRowCount++; } var toreturn = new List>(); var pushto = 0; for (int j = 0; j < columnCount; j++) { var start = j; int i = 0; var end = i; for (i = 0; i < finalRowCount; i++) { if ((i < rowCount) || ((i == rowCount) && (j < noOfCells))) { start = j; end = i; } } toreturn.Add(list.Skip(pushto).Take(end + 1)); pushto += end + 1; } return toreturn; }