2012-08-01 21 views
5

Supongamos que tengo esta lista de números:agrupar los elementos por importe total

List<int> nu = new List<int>(); 
nu.Add(2); 
nu.Add(1); 
nu.Add(3); 
nu.Add(5); 
nu.Add(2); 
nu.Add(1); 
nu.Add(1); 
nu.Add(3); 

Mantener los elementos de la lista en el mismo orden, es posible agrupar los artículos en LINQ que son suma de 6 así que los resultados serían algo de esta manera:

2,1,3 - 5 - 2,1,1 - 3 
+2

Su el resultado no se agrupa por 'menos de 7 '. Todos los números son menores que 7. – abatishchev

+3

La suma de cada grupo es menor que 7 – Johnny5

+0

¿Por qué (2,1,3) estaría en un grupo de habla a (5)? Ambos son menos de 7 – saj

Respuesta

4

Puedes hacerlo con Agregado.

(Nota: El uso LINQPad para probar/escribir este tipo de consultas, hace que sea fácil)

da a estos resultados:

results

como esto:

class Less7Holder 
{ 
    public List<int> g = new List<int>(); 
    public int mySum = 0; 
} 

void Main() 
{ 
    List<int> nu = new List<int>(); 
    nu.Add(2); 
    nu.Add(1); 
    nu.Add(3); 
    nu.Add(5); 
    nu.Add(2); 
    nu.Add(1); 
    nu.Add(1); 
    nu.Add(3); 

    var result = nu .Aggregate(
     new LinkedList<Less7Holder>(), 
     (holder,inItem) => 
     { 
      if ((holder.Last == null) || (holder.Last.Value.mySum + inItem >= 7)) 
      { 
      Less7Holder t = new Less7Holder(); 
      t.g.Add(inItem); 
      t.mySum = inItem; 
      holder.AddLast(t); 
      } 
      else 
      { 
      holder.Last.Value.g.Add(inItem); 
      holder.Last.Value.mySum += inItem; 
      } 
      return holder; 
     }, 
     (holder) => { return holder.Select((h) => h.g);}); 

    result.Dump(); 

} 
+0

+1 para la solución en LINQ como se solicitó –

6

la solución de este con LINQ directamente sería molesto, en su lugar podría hacer un método de extensión:

// Assumptions: 
// (1) All non-negative, or at least you don't mind them in your sum 
// (2) Items greater than the sum are returned by their lonesome 
static IEnumerable<IEnumerable<int>> GroupBySum(this IEnumerable<int> source, 
    int sum) 
{ 
    var running = 0; 
    var items = new List<int>(); 
    foreach (var x in source) 
    { 
     if (running + x > sum && items.Any()) 
     { 
      yield return items; 
      items = new List<int>(); 
      running = 0; 
     } 

     running += x; 
     items.Add(x); 
    } 

    if (items.Any()) yield return items; 
} 
+1

Estaba escribiendo un código similar, pero ¿por qué llamar 'ToArray' cada vez y borrar la lista existente? ¿Por qué no solo devuelve la lista y crea una nueva cada vez? –

+0

Good 'ol SE concurso de sorteo rápido. Yo estaba 73% terminado con el mismo método de extensión cuando esto se publicó. –

+0

@JonSkeet: sin motivo; gracias por la revisión (actualizada). – user7116