6

Is there a more elegant way to implement going 5 items at a time than a for loop like this?

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();
}
rid
  • 61,078
  • 31
  • 152
  • 193
Aaron Anodide
  • 16,906
  • 15
  • 62
  • 121
  • 1
    Wow. Sorry, but from the looks of the rest of the code, I **really** can't believe you had to ask this question. – Jonathon Reinhart Oct 11 '12 at 05:00
  • umm.. i was thinking someone might know how to get an iterator to resume from where it left off or something so I could say something like while(items.HasMore) Take(5).... also I might be coding too long... :) – Aaron Anodide Oct 11 '12 at 05:03
  • I think I missed what exactly you were trying to accomplish. My apologies - see my answer below. – Jonathon Reinhart Oct 11 '12 at 05:13
  • i should apologize for not being clear - in actuality i want to operate on 5 items at a time - specifically, it's a multithreaded producer consumer situation where the producer feeds 5 items, then waitd until the consumer signals that it's finished.. i'll try to think a little more before posting in the future, but I thank you for your time/help – Aaron Anodide Oct 11 '12 at 05:15

4 Answers4

11
for(int i = 0; i <= count; i+=5)
{
}
Habib
  • 219,104
  • 29
  • 407
  • 436
idstam
  • 2,848
  • 1
  • 21
  • 30
5

So you want to efficiently call Dump() on every 5 items in q.

The solution you have now will re-iterate the IEnumerable<T> every time through the for loop. It may be more efficient to do something like this: (I don't know what your type is so I'm using 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();
}

This only uses one iterator. Considering your variable is named q, I'm assuming that is short for "query", which implies this is against a database. So using just one iterator may be very beneficial.


I may keep this code, and wrap it up in an extension method. How about "clump"?

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);
}

Calling it in the context of your code:

foreach (var clump in q.Clump(5)) {
    clump.Dump();
}
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • +1. Maybe "SliceBy" (similar to GroupBy) would be better name. And here is answer (which can be found with "[C#] slice IEnumerable") that discusses options - http://stackoverflow.com/questions/1349491/how-can-i-split-an-ienumerablestring-into-groups-of-ienumerablestring. – Alexei Levenkov Oct 11 '12 at 16:14
  • 1
    Side note: your current code have bug with not reporting last chunk (i.e. items.Count() == 1) – Alexei Levenkov Oct 11 '12 at 16:18
1

try iterating by 5 instead!

for(int i = 0; i < count; i += 5) 
{
   //etc
}
ohmusama
  • 4,159
  • 5
  • 24
  • 44
1

Adding more LINQ with GroupBy and Zip:

 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.
});
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • @AaronAnodide, this is mostly for fun - Jonathon Reinhart's answer is obviously better as GroupBy is not a good pick for large collections. If you want to stay with LINQ - Aggregate would better option. – Alexei Levenkov Oct 11 '12 at 16:16