2012-08-01 19 views
5

Załóżmy, że mam tej listy numer:pozycje Grupa o łączną kwotę

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

Utrzymanie elementów listy w tej samej kolejności, jest to możliwe do grupowania elementów w LINQ, które są sumą 6 więc wyniki byłoby coś tak:

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

Twój wynik nie grupuje o 'mniej niż 7'. Wszystkie liczby są mniejsze niż 7. – abatishchev

+3

Suma każdej grupy jest mniejsza niż 7 – Johnny5

+0

Dlaczego (2,1,3) byłaby w grupie spearate (5)? Oboje są mniej niż 7 – saj

Odpowiedz

4

Możesz to zrobić za pomocą Aggregate.

(uwaga Side Use LINQPad przetestować/zapisu tego typu zapytań ułatwia)

Daje te wyniki:

results

tak:

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 dla rozwiązania w LINQ, jak zostało zadane –

6

Rozwiązanie to z LINQ bezpośrednio byłoby uciążliwe, a nie można zrobić metodę rozszerzenia:

// 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

Sam pisałem podobny kod - ale po co wywoływać "ToArray" za każdym razem i czyść istniejącą listę? Dlaczego po prostu nie zwrócisz listy i za każdym razem stworzysz nową? –

+0

Dobry konkurs na szybkie losowanie. W momencie opublikowania tego artykułu skończyłem 73% z tą samą metodą rozszerzenia. –

+0

@JonSkeet: bez powodu; dzięki za recenzję (zaktualizowane). – user7116

Powiązane problemy