2009-08-11 40 views
7

CONTEXTO

  • que tiene una lista de elementos (o longitud arbitraria). Me gustaría agruparlos en 'trozos' de cierto tamaño
  • Ejemplo: Tengo 12 clientes [0,1,2,3,4,5,6,7,8,9,10,11] y desea agrupar los trozos min de 5 que darían [0,1,2,3,4] [5,6,7,8,9] [10,11]
  • NOTA: En realidad, no estoy trabajando con clientes o aumentando monótonamente enteros. Tomé eso sólo para simplificar la pregunta

MI PREGUNTA

¿Cómo puedo formular una consulta LINQ directa (utilizando la sintaxis de consulta) que realiza esta agrupación?Linq: Cómo agrupar por número máximo de elementos

Antecedentes

  • ya estoy familiarizado con el uso de la sintaxis de LINQ para la agrupación por un valor de, por ejemplo, (a las ventas del grupo de ID de cliente), sin embargo yo estoy en una pérdida cómo expresar la 'fragmentación 'limpiar/elegantemente usando LINQ. No estoy seguro si es posible incluso de una manera directa.
  • Puedo y ya he implementado una solución en simple-old-C# sin usar la sintaxis de LINQ. Por lo tanto, mi problema no está bloqueado en esta pregunta, sino que estoy buscando formas de expresarlo en LINQ (otra vez limpia y elegantemente)
+0

posible duplicado de la [Lista de Split en sublistas con LINQ] (http://stackoverflow.com/questions/419019/split-list-into -sublists-with-linq) – nawfal

Respuesta

9

Puede agruparlos por (index/chunkSize). Ejemplo:

var result = 
     from i in array.Select((value, index) => new { Value = value, Index = index }) 
     group i.Value by i.Index/chunkSize into g 
     select g; 
+1

Este es uno de esos raros casos en los que un ciclo sencillo y un diccionario es más corto Y más comprensible que LINQ ... – Ray

+0

@Dimitriy - gracias por la respuesta @Ray - definitivamente – namenlos

+0

Buena solución ! ¡Muy útil! –

2

Para aquellos que prefieren los métodos de LINQ (con expresiones lambda), aquí se Dimitriy Matveev's answer convertidos:

var result = array 
    .Select((value, index) => new { Value = value, Index = index }) 
    .GroupBy(i => i.Index/chunkSize, v => v.Value); 

Si necesita simplemente un conjunto de value, en lugar de una IGrouping<T1, T2>, tiene que poner lo siguiente:

.Select(x => x.ToArray()) 
0

Para hacer la agrupación real, ¿no debería ser:

Método de extensión
var result = array 
.Select((value, index) => new { Value = value, Index = index}) 
.GroupBy(i => i.Index/chunk, v => v.Value); 
+0

Steven - estás en lo correcto. He actualizado mi respuesta. Gracias por atrapar eso. Además, tenga en cuenta que StackOverflow (StackExchange como un todo) no es un estilo de foro, donde usted responde a la respuesta "anterior". Usted planteó responder a la pregunta. Me doy cuenta de que probablemente no tenías suficiente representante para agregar un comentario. Entonces, de todos modos, solo intento ayudar. – Jesse

0

(usando Jesse's answer):

public static IEnumerable<T[]> GroupToChunks<T>(this IEnumerable<T> items, int chunkSize) 
{ 
    if (chunkSize <= 0) 
    { 
     throw new ArgumentException("Chunk size must be positive.", "chunkSize"); 
    } 

    return 
     items.Select((item, index) => new { item, index }) 
      .GroupBy(pair => pair.index/chunkSize, pair => pair.item) 
      .Select(grp => grp.ToArray()); 
}