【问题标题】:Split a List into smaller lists of N size [duplicate]将列表拆分为 N 大小的较小列表 [重复]
【发布时间】:2012-07-13 03:27:09
【问题描述】:

我正在尝试将一个列表拆分为一系列较小的列表。

我的问题:我的拆分列表功能没有将它们拆分为正确大小的列表。它应该将它们拆分为大小为 30 的列表,而是将它们拆分为大小为 114 的列表?

如何让我的函数将列表拆分为 X 个大小为 30 或更少的列表?

public static List<List<float[]>> splitList(List <float[]> locations, int nSize=30) 
{       
    List<List<float[]>> list = new List<List<float[]>>();

    for (int i=(int)(Math.Ceiling((decimal)(locations.Count/nSize))); i>=0; i--) {
        List <float[]> subLocat = new List <float[]>(locations); 

        if (subLocat.Count >= ((i*nSize)+nSize))
            subLocat.RemoveRange(i*nSize, nSize);
        else subLocat.RemoveRange(i*nSize, subLocat.Count-(i*nSize));

        Debug.Log ("Index: "+i.ToString()+", Size: "+subLocat.Count.ToString());
        list.Add (subLocat);
    }

    return list;
}

如果我在大小为 144 的列表上使用该函数,则输出为:

索引:4,尺寸:120
索引:3,尺寸:114
索引:2,尺寸:114
索引:1,尺寸:114
索引:0,大小:114

【问题讨论】:

  • 如果 LINQ 解决方案可以接受,this question may be of some help。
  • 特别是 Sam Saffron 对上一个问题的回答。除非这是为了学校作业,否则我会使用他的代码并停止。

标签: c# list split


【解决方案1】:

我建议使用这种扩展方法将源列表按指定的块大小分块到子列表:

/// <summary>
/// Helper methods for the lists.
/// </summary>
public static class ListExtensions
{
    public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize) 
    {
        return source
            .Select((x, i) => new { Index = i, Value = x })
            .GroupBy(x => x.Index / chunkSize)
            .Select(x => x.Select(v => v.Value).ToList())
            .ToList();
    }
}

例如,如果您将 18 个项目的列表按每个块 5 个项目分块,它会为您提供 4 个子列表的列表,其中包含以下项目:5-5-5-3。

注意:upcoming improvements to LINQ in .NET 6 分块 会像这样开箱即用:

const int PAGE_SIZE = 5;

IEnumerable<Movie[]> chunks = movies.Chunk(PAGE_SIZE);

【讨论】:

  • 在生产中使用它之前,请确保您了解运行时对内存和性能的影响。仅仅因为 LINQ 可以简洁,并不意味着它是一个好主意。
  • 当然,@Nick 我一般建议在做任何事情之前先三思。使用 LINQ 进行分块不应该是重复数千次的经常操作。通常,您需要分块列表以逐批和/或并行处理项目。
  • 我不认为内存和性能应该是一个大问题。我碰巧需要将一个包含超过 200,000 条记录的列表拆分为较小的列表,每个列表大约 3000 条,这将我带到了这个线程,我测试了这两种方法,发现运行时间几乎相同。之后,我测试了将该列表拆分为每个包含 3 条记录的列表,但性能仍然可以。我确实认为 Serj-Tm 的解决方案更直接,但具有更好的可维护性。
  • @IarekKovtunenko 很好,有数以万计的记录,您绝对应该根据您的特定需求调整算法。我会用缓冲区实现类似流处理逻辑的东西,它分两步将记录分块:1)获取第一部分 - 任何合理数量的记录(例如 10K)和 2)每个部分中的块。不要用显微镜敲钉子——使用正确的工具来完成这项任务;)
  • @DmitryPavlov 在all这段时间里,我从来不知道能够在select语句中像这样投影索引!我认为这是一个新功能,直到我注意到你在 2014 年发布了这个,这真的让我感到惊讶!谢谢你分享这个。此外,让 IEnumerable 可以使用此扩展方法并返回 IEnumerable 不是更好吗?
【解决方案2】:
public static List<List<float[]>> SplitList(List<float[]> locations, int nSize=30)  
{        
    var list = new List<List<float[]>>(); 

    for (int i = 0; i < locations.Count; i += nSize) 
    { 
        list.Add(locations.GetRange(i, Math.Min(nSize, locations.Count - i))); 
    } 

    return list; 
} 

通用版:

public static IEnumerable<List<T>> SplitList<T>(List<T> locations, int nSize=30)  
{        
    for (int i = 0; i < locations.Count; i += nSize) 
    { 
        yield return locations.GetRange(i, Math.Min(nSize, locations.Count - i)); 
    }  
} 

【讨论】:

  • 因此,如果我有一个列表长度不计其数,并且我想拆分为长度为 30 的较小列表,并且从每个较小的列表中我只想获取(1),那么我仍然会创建 30 个项目的列表其中我扔掉了 29 件物品。这可以做得更聪明!
  • 这真的有效吗?它不会在第一次拆分时失败,因为您将范围从 nSize 到 nSize?例如,如果 nSize 为 3,我的数组大小为 5,则返回的第一个索引范围为 GetRange(3, 3)
  • @MatthewPigram 已经过测试并且可以正常工作。 Math.Min 采用最小值,因此如果最后一个块小于 nSize (2
  • @HaraldCoppoolse OP 没有要求选择,只是拆分列表
  • @Jorn.Beyers 可能属于微优化类别。如果它是一个问题,它只是一个问题。微软说 .Count 是一个 O(1) 操作,所以我怀疑通过将它存储在一个变量中你会看到任何改进:docs.microsoft.com/en-us/dotnet/api/…
【解决方案3】:

怎么样:

while(locations.Any())
{    
    list.Add(locations.Take(nSize).ToList());
    locations= locations.Skip(nSize).ToList();
}

【讨论】:

  • 这会消耗大量内存吗?每次 locations.Skip.ToList 发生时,我想知道是否分配了更多内存并且新列表引用了未跳过的项目。
  • 是的,每个循环都会创建一个新列表。是的,它会消耗内存。但是,如果您遇到内存问题,这不是优化的地方,因为该列表的实例已准备好在下一个循环中收集。您可以通过跳过ToList 来换取内存的性能,但我不会费心去优化它——它是如此微不足道,而且不太可能成为瓶颈。这种实现的主要好处是它很容易理解。如果您愿意,可以使用接受的答案,它不会创建这些列表,但会更复杂一些。
  • .Skip(n) 每次调用时都会迭代 n 元素,虽然这可能没问题,但考虑性能关键代码很重要。 stackoverflow.com/questions/20002975/…
  • @Chakrava 当然,我的解决方案不适用于性能关键代码,但根据我的经验,您首先编写工作代码,然后确定什么是性能关键,并且很少执行我的 linq to objects 操作说50个物体。这应该逐案评估。
  • @Rafal 我同意,我在公司的代码库中发现了许多 .Skip()s,虽然它们可能不是“最佳”的,但它们工作得很好。无论如何,数据库操作之类的事情需要更长的时间。但我认为重要的是要注意 .Skip() 在途中“接触”每个元素 .Skip() 可能是导致难以发现的错误的原因。
【解决方案4】:

库MoreLinq 具有称为Batch 的方法

List<int> ids = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; // 10 elements
int counter = 1;
foreach(var batch in ids.Batch(2))
{
    foreach(var eachId in batch)
    {
        Console.WriteLine("Batch: {0}, Id: {1}", counter, eachId);
    }
    counter++;
}

结果是

Batch: 1, Id: 1
Batch: 1, Id: 2
Batch: 2, Id: 3
Batch: 2, Id: 4
Batch: 3, Id: 5
Batch: 3, Id: 6
Batch: 4, Id: 7
Batch: 4, Id: 8
Batch: 5, Id: 9
Batch: 5, Id: 0

ids 被分成 2 个元素的 5 个块。

【讨论】:

  • 这必须是公认的答案。或者至少在这个页面上高很多。
  • 同意,我专门来这里是因为我知道会有一个 MoreLinq 答案。
  • 这其实是最好的答案。
【解决方案5】:

Serj-Tm 解决方案很好,这也是作为列表扩展方法的通用版本(放入静态类):

public static List<List<T>> Split<T>(this List<T> items, int sliceSize = 30)
{
    List<List<T>> list = new List<List<T>>();
    for (int i = 0; i < items.Count; i += sliceSize)
        list.Add(items.GetRange(i, Math.Min(sliceSize, items.Count - i)));
    return list;
} 

【讨论】:

    【解决方案6】:

    .NET 6 更新

    var originalList = new List<int>{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
    
    // split into arrays of no more than three
    IEnumerable<int[]> chunks = originalList.originalList.Chunk(3);
    

    .NET 6 之前

    public static IEnumerable<IEnumerable<T>> SplitIntoSets<T>
        (this IEnumerable<T> source, int itemsPerSet) 
    {
        var sourceList = source as List<T> ?? source.ToList();
        for (var index = 0; index < sourceList.Count; index += itemsPerSet)
        {
            yield return sourceList.Skip(index).Take(itemsPerSet);
        }
    }
    

    【讨论】:

    • 这是一个 O(n) 复杂度的好答案。
    【解决方案7】:

    我发现公认的答案 (Serj-Tm) 最可靠,但我想建议一个通用版本。

    public static List<List<T>> splitList<T>(List<T> locations, int nSize = 30)
    {
        var list = new List<List<T>>();
    
        for (int i = 0; i < locations.Count; i += nSize)
        {
            list.Add(locations.GetRange(i, Math.Min(nSize, locations.Count - i)));
        }
    
        return list;
    }
    

    【讨论】:

      【解决方案8】:

      虽然上面的许多答案都可以完成工作,但它们都在永无止境的序列(或非常长的序列)上失败了。以下是一个完全在线的实现,它保证了可能的最佳时间和内存复杂性。我们只迭代源可枚举一次并使用 yield return 进行惰性评估。消费者可以在每次迭代时丢弃列表,使内存占用等于带有 batchSize 元素数量的列表。

      public static IEnumerable<List<T>> BatchBy<T>(this IEnumerable<T> enumerable, int batchSize)
      {
          using (var enumerator = enumerable.GetEnumerator())
          {
              List<T> list = null;
              while (enumerator.MoveNext())
              {
                  if (list == null)
                  {
                      list = new List<T> {enumerator.Current};
                  }
                  else if (list.Count < batchSize)
                  {
                      list.Add(enumerator.Current);
                  }
                  else
                  {
                      yield return list;
                      list = new List<T> {enumerator.Current};
                  }
              }
      
              if (list?.Count > 0)
              {
                  yield return list;
              }
          }
      }
      

      编辑:刚刚意识到 OP 要求将 List&lt;T&gt; 分解为更小的 List&lt;T&gt;,因此我关于无限可枚举的 cmets 不适用于 OP,但可能会帮助到这里的其他人。这些 cmets 是为了响应其他发布的解决方案,这些解决方案确实使用 IEnumerable&lt;T&gt; 作为其函数的输入,但多次枚举源可枚举。

      【讨论】:

      • 我认为IEnumerable&lt;IEnumerable&lt;T&gt;&gt; 版本更好,因为它不涉及太多List 构造。
      • @NetMage - IEnumerable&lt;IEnumerable&lt;T&gt;&gt; 的一个问题是实现可能依赖于消费者完全枚举每个产生的内部枚举。我确信可以通过某种方式来避免该问题的解决方案,但我认为生成的代码可能会很快变得复杂。此外,由于它是惰性的,我们一次只生成一个列表,并且每个列表只发生一次内存分配,因为我们预先知道大小。
      • 你是对的 - 我的实现使用了一种新类型的枚举器(位置枚举器),它跟踪你当前的位置,包装一个标准的枚举器,让你移动到一个新的位置。
      【解决方案9】:

      最后加上非常有用的mhand注释

      原答案

      虽然大多数解决方案可能有效,但我认为它们的效率并不高。假设您只想要前几个块的前几个项目。那么你就不想遍历序列中的所有(无数)项。

      以下内容最多会列举两次:一次用于 Take,一次用于 Skip。它不会枚举比您将使用的元素更多的元素:

      public static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource>
          (this IEnumerable<TSource> source, int chunkSize)
      {
          while (source.Any())                     // while there are elements left
          {   // still something to chunk:
              yield return source.Take(chunkSize); // return a chunk of chunkSize
              source = source.Skip(chunkSize);     // skip the returned chunk
          }
      }
      

      这将枚举序列多少次?

      假设您将源分成chunkSize 的块。您仅枚举前 N 个块。从每个枚举块中,您只会枚举前 M 个元素。

      While(source.Any())
      {
           ...
      }
      

      Any 会获取 Enumerator,做 1 MoveNext() 并在 Disposing Enumerator 后返回返回值。这将完成 N 次

      yield return source.Take(chunkSize);
      

      根据reference source,这将执行以下操作:

      public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, int count)
      {
          return TakeIterator<TSource>(source, count);
      }
      
      static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
      {
          foreach (TSource element in source)
          {
              yield return element;
              if (--count == 0) break;
          }
      }
      

      在您开始枚举获取的块之前,这并没有多大作用。如果您获取多个 Chunk,但决定不枚举第一个 Chunk,则不会执行 foreach,因为您的调试器会向您显示。

      如果你决定取第一个块的前 M 个元素,那么 yield return 将被执行 M 次。这意味着:

      • 获取枚举器
      • 调用 MoveNext() 和 Current M 次。
      • 配置枚举器

      在第一个chunk被yield返回后,我们跳过这个第一个chunk:

      source = source.Skip(chunkSize);
      

      再次:我们将查看reference source 以找到skipiterator

      static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
      {
          using (IEnumerator<TSource> e = source.GetEnumerator()) 
          {
              while (count > 0 && e.MoveNext()) count--;
              if (count <= 0) 
              {
                  while (e.MoveNext()) yield return e.Current;
              }
          }
      }
      

      如您所见,SkipIterator 为 Chunk 中的每个元素调用一次 MoveNext()。 它不会调用Current。

      因此,我们看到每个 Chunk 都完成了以下操作:

      • Any():GetEnumerator; 1 移动下一个();处置枚举器;
      • Take():

        • 如果没有枚举块的内容,则什么都没有。
        • 如果枚举内容:GetEnumerator(),每个枚举项一个 MoveNext 和一个 Current,Dispose 枚举器;

        • Skip():对于每个枚举的块(不是块的内容): GetEnumerator(), MoveNext() chunkSize 次,没有 Current!配置枚举器

      如果您查看枚举器发生的情况,您会发现有很多对 MoveNext() 的调用,并且仅对您实际决定访问的 TSource 项调用 Current。

      如果你取 N 个大小为 chunkSize 的 Chunks,则调用 MoveNext()

      • Any() N 次
      • 还没有时间进行 Take,只要您不枚举块
      • Skip() 的 N 倍 chunkSize

      如果您决定只枚举每个获取的块的前 M 个元素,那么您需要对每个枚举的块调用 MoveNext M 次。

      总数

      MoveNext calls: N + N*M + N*chunkSize
      Current calls: N*M; (only the items you really access)
      

      所以如果你决定枚举所有块的所有元素:

      MoveNext: numberOfChunks + all elements + all elements = about twice the sequence
      Current: every item is accessed exactly once
      

      MoveNext 是否需要大量工作,取决于源序列的类型。对于列表和数组,它是一个简单的索引增量,可能会进行超出范围检查。

      但是如果您的 IEnumerable 是数据库查询的结果,请确保数据确实在您的计算机上实现,否则数据将被多次获取。 DbContext 和 Dapper 会在数据被访问之前正确地将数据传输到本地进程。如果您多次枚举相同的序列,则不会多次获取它。 Dapper 返回一个 List 对象,DbContext 记住数据已经被获取。

      在开始划分块中的项目之前调用 AsEnumerable() 或 ToLists() 是否明智,取决于您的存储库

      【讨论】:

      • 这不会枚举两次 per 批次吗?所以我们真的在枚举源2*chunkSize 次?这取决于可枚举的来源(可能是数据库支持或其他非记忆来源),这是致命的。想象一下这个可枚举作为输入 Enumerable.Range(0, 10000).Select(i =&gt; DateTime.UtcNow) - 每次枚举该可枚举时都会得到不同的时间,因为它没有被记忆
      • 考虑:Enumerable.Range(0, 10).Select(i =&gt; DateTime.UtcNow)。通过调用Any,您每次都将重新计算当前时间。对于DateTime.UtcNow 来说还不错,但考虑一个由数据库连接/sql 游标或类似物支持的可枚举。我已经看到由于开发人员不了解“可枚举的多个枚举”的潜在影响而发出数千个 DB 调用的案例——ReSharper 也为此提供了提示
      【解决方案10】:

      我有一个通用方法,它可以采用任何类型,包括浮点数,并且已经过单元测试,希望对您有所帮助:

          /// <summary>
          /// Breaks the list into groups with each group containing no more than the specified group size
          /// </summary>
          /// <typeparam name="T"></typeparam>
          /// <param name="values">The values.</param>
          /// <param name="groupSize">Size of the group.</param>
          /// <returns></returns>
          public static List<List<T>> SplitList<T>(IEnumerable<T> values, int groupSize, int? maxCount = null)
          {
              List<List<T>> result = new List<List<T>>();
              // Quick and special scenario
              if (values.Count() <= groupSize)
              {
                  result.Add(values.ToList());
              }
              else
              {
                  List<T> valueList = values.ToList();
                  int startIndex = 0;
                  int count = valueList.Count;
                  int elementCount = 0;
      
                  while (startIndex < count && (!maxCount.HasValue || (maxCount.HasValue && startIndex < maxCount)))
                  {
                      elementCount = (startIndex + groupSize > count) ? count - startIndex : groupSize;
                      result.Add(valueList.GetRange(startIndex, elementCount));
                      startIndex += elementCount;
                  }
              }
      
      
              return result;
          }
      

      【讨论】:

      • 谢谢。想知道是否可以使用 maxCount 参数定义更新 cmets?安全网?
      • 谨慎使用可枚举的多个枚举。 values.Count() 将导致一个完整的枚举,然后 values.ToList() 另一个。 values = values.ToList() 更安全,所以它已经实现了。
      【解决方案11】:
      public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> items, int maxItems)
      {
          return items.Select((item, index) => new { item, index })
                      .GroupBy(x => x.index / maxItems)
                      .Select(g => g.Select(x => x.item));
      }
      

      【讨论】:

      • 我们可以将其发送到class,而不是.Select(g =&gt; g.Select(x =&gt; x.item));,比如.Select(g =&gt; g.Select(x =&gt; new { v = x.item})); 吗?
      【解决方案12】:

      从 .NET 6.0 开始,您可以使用 LINQ 扩展 Chunk&lt;T&gt;() 将枚举拆分为块。 Docs

      var chars = new List<char>() { 'h', 'e', 'l', 'l', 'o', 'w','o','r' ,'l','d' };
      foreach (var batch in chars.Chunk(2))
      {
          foreach (var ch in batch)
          {
              // iterates 2 letters at a time
          }
      }
      

      【讨论】:

      • .NET CORE 怎么样?
      【解决方案13】:

      这个怎么样?这个想法是只使用一个循环。而且,谁知道呢,也许您在代码中只使用 IList 实现,并且您不想强制转换为 List。

      private IEnumerable<IList<T>> SplitList<T>(IList<T> list, int totalChunks)
      {
          IList<T> auxList = new List<T>();
          int totalItems = list.Count();
      
          if (totalChunks <= 0)
          {
              yield return auxList;
          }
          else 
          {
              for (int i = 0; i < totalItems; i++)
              {               
                  auxList.Add(list[i]);           
      
                  if ((i + 1) % totalChunks == 0)
                  {
                      yield return auxList;
                      auxList = new List<T>();                
                  }
      
                  else if (i == totalItems - 1)
                  {
                      yield return auxList;
                  }
              }
          }   
      }
      

      【讨论】:

        【解决方案14】:

        还有一个

        public static IList<IList<T>> SplitList<T>(this IList<T> list, int chunkSize)
        {
            var chunks = new List<IList<T>>();
            List<T> chunk = null;
            for (var i = 0; i < list.Count; i++)
            {
                if (i % chunkSize == 0)
                {
                    chunk = new List<T>(chunkSize);
                    chunks.Add(chunk);
                }
                chunk.Add(list[i]);
            }
            return chunks;
        }
        

        【讨论】:

          【解决方案15】:
          public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize)
              {           
                  var result = new List<List<T>>();
                  for (int i = 0; i < source.Count; i += chunkSize)
                  {
                      var rows = new List<T>();
                      for (int j = i; j < i + chunkSize; j++)
                      {
                          if (j >= source.Count) break;
                          rows.Add(source[j]);
                      }
                      result.Add(rows);
                  }
                  return result;
              }
          

          【讨论】:

            【解决方案16】:

            在 .NET 6 中,您可以只使用 source.Chunk(chunkSize)

            基于 Serj-Tm 接受的答案的更通用的版本。

                public static IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> source, int size = 30)
                {
                    var count = source.Count();
                    for (int i = 0; i < count; i += size)
                    {
                        yield return source
                            .Skip(Math.Min(size, count - i))
                            .Take(size);
                    }
                }
            

            【讨论】:

            • IEnumerable&lt;T&gt; 来源不应被列举不止一次。不能保证每个枚举都很便宜,或者后续枚举会产生与前一个枚举相同的项目。
            【解决方案17】:

            我也遇到过同样的需求,我结合使用了 Linq 的 Skip() 和 Take() 方法。我将我取的数字乘以到目前为止的迭代次数,得到要跳过的项目数,然后我取下一组。

                    var categories = Properties.Settings.Default.MovementStatsCategories;
                    var items = summariesWithinYear
                        .Select(s =>  s.sku).Distinct().ToList();
            
                    //need to run by chunks of 10,000
                    var count = items.Count;
                    var counter = 0;
                    var numToTake = 10000;
            
                    while (count > 0)
                    {
                        var itemsChunk = items.Skip(numToTake * counter).Take(numToTake).ToList();
                        counter += 1;
            
                        MovementHistoryUtilities.RecordMovementHistoryStatsBulk(itemsChunk, categories, nLogger);
            
                        count -= numToTake;
                    }
            

            【讨论】:

              【解决方案18】:

              基于Dimitry Pavlov answere,我将删除.ToList()。并且还要避免匿名类。 相反,我喜欢使用不需要堆内存分配的结构。 (ValueTuple 也可以。)

              public static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource>(this IEnumerable<TSource> source, int chunkSize)
              {
                  if (source is null)
                  {
                      throw new ArgumentNullException(nameof(source));
                  }
                  if (chunkSize <= 0)
                  {
                      throw new ArgumentOutOfRangeException(nameof(chunkSize), chunkSize, "The argument must be greater than zero.");
                  }
              
                  return source
                      .Select((x, i) => new ChunkedValue<TSource>(x, i / chunkSize))
                      .GroupBy(cv => cv.ChunkIndex)
                      .Select(g => g.Select(cv => cv.Value));
              } 
              
              [StructLayout(LayoutKind.Auto)]
              [DebuggerDisplay("{" + nameof(ChunkedValue<T>.ChunkIndex) + "}: {" + nameof(ChunkedValue<T>.Value) + "}")]
              private struct ChunkedValue<T>
              {
                  public ChunkedValue(T value, int chunkIndex)
                  {
                      this.ChunkIndex = chunkIndex;
                      this.Value = value;
                  }
              
                  public int ChunkIndex { get; }
              
                  public T Value { get; }
              }
              

              这可以像下面这样使用,它只迭代一次集合,然后 也不会分配任何重要的内存。

              int chunkSize = 30;
              foreach (var chunk in collection.ChunkBy(chunkSize))
              {
                  foreach (var item in chunk)
                  {
                      // your code for item here.
                  }
              }
              

              如果确实需要一个具体的列表,那么我会这样做:

              int chunkSize = 30;
              var chunkList = new List<List<T>>();
              foreach (var chunk in collection.ChunkBy(chunkSize))
              {
                  // create a list with the correct capacity to be able to contain one chunk
                  // to avoid the resizing (additional memory allocation and memory copy) within the List<T>.
                  var list = new List<T>(chunkSize);
                  list.AddRange(chunk);
                  chunkList.Add(list);
              }
              

              【讨论】:

                【解决方案19】:
                List<int> orginalList =new List<int>(){1,2,3,4,5,6,7,8,9,10,12};
                Dictionary<int,List<int>> dic = new Dictionary <int,List<int>> ();
                int batchcount = orginalList.Count/2; //To List into two 2 parts if you 
                 want three give three
                List<int> lst = new List<int>();
                for (int i=0;i<orginalList.Count; i++)
                {
                lst.Add(orginalList[i]);
                if (i % batchCount == 0 && i!=0)
                {
                Dic.Add(threadId, lst);
                lst = new List<int>();**strong text**
                threadId++;
                }
                }
                if(lst.Count>0)
                Dic.Add(threadId, lst); //in case if any dayleft 
                foreach(int BatchId in Dic.Keys)
                {
                  Console.Writeline("BatchId:"+BatchId);
                  Console.Writeline('Batch Count:"+Dic[BatchId].Count);
                }
                

                【讨论】:

                • 最好是解释你的答案,而不是只提供一个代码 sn-p
                • 最好在发布之前运行您的代码。您将 Dictionary 声明为dic,但稍后将其用作Dic。你没有声明lstdocs。很确定这些会产生编译错误!
                • 对不起,我没有注意到,现在你可以试试。谢谢
                【解决方案20】:

                您可以只使用 LINQ 尝试以下代码:

                public static IList<IList<T>> Split<T>(IList<T> source)
                {
                    return  source
                        .Select((x, i) => new { Index = i, Value = x })
                        .GroupBy(x => x.Index / 3)
                        .Select(x => x.Select(v => v.Value).ToList())
                        .ToList();
                }
                

                【讨论】:

                  【解决方案21】:

                  如果你想用条件而不是固定数字来分割它:

                  ///<summary>
                  /// splits a list based on a condition (similar to the split function for strings)
                  ///</summary>
                  public static IEnumerable<List<T>> Split<T>(this IEnumerable<T> src, Func<T, bool> pred)
                  {
                      var list = new List<T>();
                      foreach(T item in src)
                      {   
                          if(pred(item))
                          {
                              if(list != null && list.Count > 0)
                                  yield return list;
                                  
                              list = new List<T>();
                          }
                          else
                          {
                              list.Add(item);
                          }
                      }
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2012-07-12
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-02-02
                    • 2020-05-05
                    • 1970-01-01
                    • 2012-03-29
                    • 1970-01-01
                    • 2012-11-04
                    相关资源
                    最近更新 更多