【问题标题】:Is there another way to take N at a time than a for loop?除了for循环之外,还有另一种方法可以一次取N吗?
【发布时间】:2012-10-01 16:47:51
【问题描述】:

有没有比这样的 for 循环更优雅的方式来一次执行 5 个项目?

var q = Campaign_stats.OrderByDescending(c=>c.Leads).Select(c=>c.PID).Take(23);
var count = q.Count();
for (int i = 0; i < (count/5)+1; i++)
{
   q.Skip(i*5).Take(5).Dump();
}

【问题讨论】:

  • 哇。抱歉,但从其余代码的外观来看,我真的不敢相信你不得不问这个问题。
  • umm.. 我在想有人可能知道如何让迭代器从它停止的地方恢复或其他什么,所以我可以说类似 while(items.HasMore) Take(5)... . 而且我可能编码太长了... :)
  • 我想我错过了你想要完成的事情。我很抱歉 - 请参阅下面的答案。
  • 我应该为不清楚而道歉 - 实际上我想一次操作 5 个项目 - 具体来说,这是一个多线程生产者消费者情况,生产者提供 5 个项目,然后等到消费者发出信号它已经完成了..我会在以后发布之前尝试多想一下,但我感谢您的时间/帮助

标签: c# linq for-loop iteration


【解决方案1】:
for(int i = 0; i <= count; i+=5)
{
}

【讨论】:

    【解决方案2】:

    因此,您希望对 q 中的每 5 个项目有效地调用 Dump()

    您现在拥有的解决方案将在每次通过for 循环时重新迭代IEnumerable&lt;T&gt;。这样做可能更有效:(我不知道你的类型是什么,所以我使用T

    const int N = 5;
    T[] ar = new T[N];               // Temporary array of N items.
    int i=0;
    foreach(var item in q) {         // Just one iterator.
        ar[i++] = item;              // Store a reference to this item.
        if (i == N) {                // When we have N items,
            ar.Dump();               // dump them,
            i = 0;                   // and reset the array index.
        }
    }
    
    // Dump the remaining items
    if (i > 0) {
        ar.Take(i).Dump();
    }
    

    这仅使用一个迭代器。考虑到您的变量名为q,我假设它是“查询”的缩写,这意味着这是针对数据库的。因此,仅使用一个迭代器可能会非常有益。


    我可以保留此代码,并将其包装在扩展方法中。 “丛”怎么说?

    public static IEnumerable<IEnumerable<T>> Clump<T>(this IEnumerable<T> items, int clumpSize) { 
        T[] ar = new T[clumpSize];
        int i=0;
        foreach(var item in items) {
            ar[i++] = item;
            if (i == clumpSize) {
                yield return ar;
                i = 0;
            }
        }
        if (i > 0)
            yield return ar.Take(i);
    }
    

    在您的代码上下文中调用它:

    foreach (var clump in q.Clump(5)) {
        clump.Dump();
    }
    

    【讨论】:

    • +1。也许“SliceBy”(类似于 GroupBy)会是更好的名字。这是讨论选项的答案(可以通过“[C#] slice IEnumerable”找到)-stackoverflow.com/questions/1349491/…
    • 旁注:您当前的代码存在未报告最后一个块的错误(即 items.Count() == 1)
    【解决方案3】:

    尝试迭代 5!

    for(int i = 0; i < count; i += 5) 
    {
       //etc
    }
    

    【讨论】:

      【解决方案4】:

      使用 GroupBy 和 Zip 添加更多 LINQ:

       q
      // add indexes
      .Zip(Enumerable.Range(0, Int32.MaxValue),(a,index)=> new {Index=index, Value=a})
      .GroupBy(m=>m.Index /5) // divide in groups by 5 items each
      .Select(k => { 
          k.Select(v => v.Value).Dump(); // Perform operation on 5 elements
          return k.Key; // return something to satisfy Select.
      });
      

      【讨论】:

      • @AaronAnodide,这主要是为了好玩——Jonathon Reinhart 的回答显然更好,因为 GroupBy 不是大型收藏的好选择。如果您想继续使用 LINQ - Aggregate 会是更好的选择。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-23
      • 1970-01-01
      • 2019-10-16
      • 1970-01-01
      • 2017-04-24
      • 2019-09-14
      • 2015-09-15
      相关资源
      最近更新 更多