2012-10-11 7 views
5

Czy istnieje bardziej elegancki sposób na wdrożenie 5 elementów naraz niż w pętli for?Czy istnieje inny sposób na wzięcie N na raz niż pętli for?

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(); 
} 
+1

Wow. Przykro mi, ale z wyglądu reszty kodu, naprawdę nie mogę uwierzyć, że musiałaś zadać to pytanie. –

+0

umm .. myślałem, że ktoś może wiedzieć, jak uzyskać iterator, aby wznowić od miejsca, w którym zostało przerwane, lub coś takiego, żebym mógł powiedzieć coś w stylu while (items.HasMore) Take (5) .... również mógłbym kodować zbyt długo ... :) –

+0

Chyba brakowało mi tego, co dokładnie próbowaliście osiągnąć. Moje przeprosiny - zobacz moją odpowiedź poniżej. –

Odpowiedz

5

więc chcesz skutecznie wywołać Dump() na każde 5 pozycji w q.

Rozwiązanie, które teraz posiadasz, ponownie przetworzy IEnumerable<T> za każdym razem poprzez pętlę for. To może być bardziej efektywne, aby zrobić coś takiego: (Nie wiem co Twój typ jest więc używam 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(); 
} 

ta korzysta tylko z jednego iterator. Biorąc pod uwagę zmienną o nazwie q, zakładam, że jest to skrót od "query", co oznacza, że ​​jest to sprzeczne z bazą danych. Zatem użycie tylko jednego iteratora może być bardzo korzystne.


Mogę zachować ten kod i zawinąć go w metodę rozszerzenia. Co powiesz na "kępę"?

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

Nazywając to w kontekście kodzie:

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

+1. Może "SliceBy" (podobny do GroupBy) byłoby lepszą nazwą. I tutaj jest odpowiedź (którą można znaleźć za pomocą "[C#] slice IEnumerable"), która omawia opcje - http://stackoverflow.com/questions/1349491/how-can-i-split-an-ienumerablestring-into-groups- z ienumerablestring. –

+1

Uwaga boczna: Twój obecny kod zawiera błąd z brakiem zgłaszania ostatniej porcji (tzn. Items.Count() == 1) –

+0

@AlexeiLevenkov Naprawiono! –

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

+1 dobry i szybki :) – Habib

+0

Dziękuję za sformułowanie. – idstam

1

try Iteracja przez 5 zamiast!

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

Dodajesz więcej LINQ z GroupBy i 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. 
}); 
+0

Wow, nigdy bym nie pomyślał o tym - fajne –

+0

@AaronAnodide, to głównie dla zabawy - odpowiedź Jonathona Reinharta jest oczywiście lepsza, ponieważ GroupBy nie jest dobrym wyborem dla dużych kolekcji. Jeśli chcesz pozostać przy LINQ - Aggregate będzie lepszą opcją. –

Powiązane problemy