2012-10-11 63 views
5

¿Existe alguna manera más elegante de implementar ir 5 elementos a la vez que un bucle for como este?¿Hay alguna otra manera de tomar N a la vez que un ciclo 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. Lo siento, pero a juzgar por el resto del código, ** realmente ** no puedo creer que tengas que hacer esta pregunta. –

+0

umm ... estaba pensando que alguien podría saber cómo obtener un iterador para reanudarlo desde donde lo dejó o algo así para poder decir algo así como while (items.HasMore) Take (5) .... también podría estar codificando también mucho ... :) –

+0

Creo que me perdí lo que exactamente estabas tratando de lograr. Mis disculpas: mira mi respuesta a continuación. –

Respuesta

5

Así que desea llamar de manera eficiente Dump() de cada 5 artículos en q.

La solución que tiene ahora volverá a iterar el IEnumerable<T> cada vez a través del bucle for. Puede ser más eficiente para hacer algo como esto: (No sé lo que su tipo es por lo que estoy usando 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(); 
} 

Esto sólo usa un iterador. Teniendo en cuenta que su variable se llama q, asumo que es la abreviatura de "consulta", lo que implica que esto va en contra de una base de datos. Entonces, usar solo un iterador puede ser muy beneficioso.


Es posible que conserve este código y lo termine en un método de extensión. ¿Qué tal "agrupar"?

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

Llamándola en el contexto de su código:

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

+1. Tal vez "SliceBy" (similar a GroupBy) sería un nombre mejor. Y aquí está la respuesta (que se puede encontrar con "[C#] slice IEnumerable") que analiza las opciones - http://stackoverflow.com/questions/1349491/how-can-i-split-an-ienumerablestring- into-groups- de-ienumedadestring. –

+1

Nota al margen: su código actual tiene error al no informar el último fragmento (es decir, items.Count() == 1) –

+0

@AlexeiLevenkov ¡Solucionado! –

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

+1 buena y rápida también :) – Habib

+0

Gracias por formatearla. – idstam

1

intento por iteración 5 en vez!

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

La adición de más de LINQ con GroupBy y Código Postal:

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

guau, nunca lo hubiera pensado - genial –

+0

@AaronAnodide, esto es principalmente por diversión - La respuesta de Jonathon Reinhart es obviamente mejor ya que GroupBy no es una buena elección para grandes colecciones. Si quieres quedarte con LINQ, agrega una mejor opción. –

Cuestiones relacionadas