【问题标题】:Process a list with a loop, taking 100 elements each time and automatically less than 100 at the end of the list用循环处理一个列表,每次取100个元素,在列表末尾自动小于100个
【发布时间】:2015-08-22 01:17:15
【问题描述】:

有没有办法使用一个循环来获取一个大列表中的前 100 个项目,对它们做一些事情,然后是下一个 100 等等,但是当它接近尾声时,它会自动缩短项目的“100”步骤剩下的。

目前我必须使用两个 if 循环:

for (int i = 0; i < listLength; i = i + 100)
{
    if (i + 100 < listLength)
    {
        //Does its thing with a bigList.GetRange(i, 100)
    }
    else
    {
        //Does the same thing with bigList.GetRange(i, listLength - i)
    }
}

有没有更好的方法来做到这一点?如果不是,我至少会让“事物”成为一个函数,这样代码就不必复制两次了。

【问题讨论】:

  • Split List into Sublists with LINQ 的可能重复项 - 这种分块行为正是我们所要求的,仅使用 LINQ,而不仅仅是使用普通循环和变量。所以,也许不是完全重复,但仍然值得考虑和阅读。

标签: c# list loops range


【解决方案1】:

您可以将一个大列表按限制拆分为多个小列表,如下所示:

var limit = 100;
foreach (var smallList in bigList.Select((x, i) => new { Index = i, Value = x })
                                 .GroupBy(x => x.Index / limit)
                                 .Select(x => x.Select(v => v.Value).ToList())
                                 .ToList())
{
    Console.WriteLine($"{smallList.Count}");
    Console.WriteLine(String.Join("\r\n", smallList));
}

【讨论】:

    【解决方案2】:

    这是我的解决方案,首先,我在到达数组顶部后跳过最后一行(rows - skiplast)。

        [TestMethod]
        public void SkipTake()
        {
            var rows = 100;
            var skip = 1;
            var skiplast = 95;
            var result = Enumerable.Range(1, rows).Take(rows - skiplast).Skip(skip - 1 == 0 ? 1 : skip).ToList();
        }
    

    【讨论】:

      【解决方案3】:

      您也可以尝试以下方法:

              int i = 1;
              foreach (item x in bigList)
              {
      
                  batchOperation.Insert(x); //replace it with your action; create the batch
                  i++;
                  if (i >100)
                  {
                      table.ExecuteBatch(batchOperation); //execute the batch
                      batchOperation.Clear();
                      i = 1; // re-initialize 
                  }
      
              }
      
              if (batchOperation.Count >= 1 )
              {
                  table.ExecuteBatch(batchOperation); //do this for the residue items 
              }
      

      【讨论】:

        【解决方案4】:

        我不喜欢列出的任何答案,所以我做了自己的扩展:

        public static class IEnumerableExtensions
        {
            public static IEnumerable<IEnumerable<T>> MakeGroupsOf<T>(this IEnumerable<T> source, int count)
            {
                var grouping = new List<T>();
                foreach (var item in source)
                {
                    grouping.Add(item);
                    if(grouping.Count == count)
                    {
                        yield return grouping;
                        grouping = new List<T>();
                    }
                }
        
                if (grouping.Count != 0)
                {
                    yield return grouping;
                }
            }
        }
        

        然后就可以使用了:

        foreach(var group in allItems.MakeGroupsOf(100))
        {
            // Do something
        }
        

        【讨论】:

        • 这也正是我想要的。 Skip+Take 似乎你每次都从元素 0 重新开始,而这实际上只是迭代列表一次,并产生一堆。
        • 这是正确的答案,尽管我会放弃使用 grouping 名称,因为 Groupings 已经是一个概念。它可能会引起混乱。更不用说 group 是某些 c# 版本中的关键字,并且在您的第二个 sn-p 中可能会导致编译器错误。
        【解决方案5】:

        您可以使用 LINQ Skip 和 Take,您的代码会更干净。

        for (int i = 0; i < listLength; i=i+100)
        {
            var items = bigList.Skip(i).Take(100); 
            // Do something with 100 or remaining items
        }
        

        注意:如果项目少于 100,Take 会给你剩下的。

        【讨论】:

        • 谢谢,就像一个魅力。也很清楚!我需要一串列表项,因此它变成了:string.Join(",", idList.Skip(i).Take(100))
        • 如果我不知道列表长度并且无法获取列表项的数量怎么办?
        • @ShekharReddy 在 C# 中有 2 种方法可以获取 var listLength = bigList.Count,您可以在 this answer 上找到更多信息
        • 太棒了,这正是我想要的。干净简单 +1
        【解决方案6】:
        List<int> list = null;
        int amount_of_hundreds = Math.Floor(list.Count/100);
        int remaining_number = list.Count - (amount_of_hundreds * 100);
        
        for(int i = 0; i < amount_of_hundreds; ++i)
            {
            for(int j = 0; j < 100; ++j)
                {
                int item = list[(i * 100) + j];
                // do what you want with item
                }
            }
        
         for(int i = 0; i < remaining_number; ++i)
            {
            int item = list[(amount_of_hundreds * 100) + i];
            // do what you want with item
            }
        

        【讨论】:

        • @quetzalcoatl - 将 0 修改为 i,但是手动和重复是什么意思?
        • 大部分只有三个:“// do you want with item”需要写两次(是的,小东西,但是新手不会想到方法,会复制粘贴正文) ,主循环和结束循环是分开的(为什么?似乎没有任何收获。可以用Math.min 将它们压缩成一个),“amount_of_hundreds;remaining_number”可以使用 div-mod 而不是手动计算“剩余”部分。只是化妆品。
        【解决方案7】:

        您可以为端点保留一个显式变量:

        for (int i = 0, j; i < listLength; i = j)
        {
            j = Math.min(listLength, i + 100);
            // do your thing with bigList.GetRange(i, j)
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-01-21
          • 2023-03-21
          • 1970-01-01
          • 2015-02-10
          • 1970-01-01
          • 2023-01-02
          • 2018-02-25
          • 2022-01-25
          相关资源
          最近更新 更多