2016-01-04 15 views
5

Ho le seguenti entità:Linq GROUP BY e somma i problemi

Una classe account con un elenco di sottoscrizioni:

public class Account 
{ 
    /// <summary> 
    /// Account ID 
    /// </summary> 
    public string ID { get; set; } 

    /// <summary> 
    /// A List with all subscriptions 
    /// </summary> 
    public IEnumerable<Subscription> Subscriptions { get; set; } 
} 

la classe di sottoscrizione con una lista di varianti e add ons:

public class Subscription 
{ 
    /// <summary> 
    /// Subscription ID 
    /// </summary> 
    public string ID { get; set; } 

    /// <summary> 
    /// Quantity of the subscription. 
    /// </summary> 
    public int Quantity { get; set; } 

    /// <summary> 
    /// A list with all subscription add ons 
    /// </summary> 
    public IEnumerable<AddOn> AddOns { get; set; } 

    /// <summary> 
    /// A List with all subscription variations 
    /// </summary> 
    public IEnumerable<Variation> Variations { get; set; } 
} 

l'add on di classe con una lista di varianti:

public class AddOn 
{ 
    /// <summary> 
    /// Gets or Sets add on id 
    /// </summary> 
    public string ID { get; set; } 

    /// <summary> 
    /// Quantity of the add on. 
    /// </summary> 
    public int Quantity { get; set; } 

    /// <summary> 
    /// A List with all add on variations 
    /// </summary> 
    public IEnumerable<Variation> Variations { get; set; } 

} 

E la classe di variazione:

public class Variation 
{ 
    /// <summary> 
    /// Variation ID 
    /// </summary> 
    public string ID { get; set; } 

    /// <summary> 
    /// offerUri 
    /// </summary> 
    public string Code { get; set; } 

    /// <summary> 
    /// Variation Value 
    /// </summary> 
    public string Value { get; set; } 

    /// <summary> 
    /// Variation Name 
    /// </summary> 
    public string Name { get; set; } 

} 

Quello che sto cercando di fare è quello di raggruppare tutti add ons con il codice specifico e sommare la quantità. Per esempio ho provato:

var groupAddOnsByCode = acc.Subscriptions.Select(s => s.AddOns.GroupBy(a => a.Variations.Select(v => v.Code).FirstOrDefault())).ToList(); 

Questo uno gruppi corretti add ons, ma voglio una lista con con add ons per gruppo sottoscrizione da parte di codice e la quantità totale per il codice.

Ad esempio se un abbonamento ha il numero X di componenti aggiuntivi e il codice di ogni componente aggiuntivo è 1, 2, ..., X, desidero raggruppare per add-on per codice e quantità totale con questo codice. Mi aspetto che il risultato sarà qualcosa di simile se ho la seguente struttura:

Una pseudo-codice con struttura attuale (codice si riferisce a Variazione classe che ogni add on ha):

Subscription { 
//a list with X number of add ons 
AddOn1 = { Variation = { Code = 1 }, Quantity = 2 }, 
AddOn2 = { Variation = { Code = 2 }, Quantity = 3 }, 
... 
AddOnX = { Variation = { Code = X }, Quantity = 4 } 
} 

Quello che mi aspetto:

Subscription { 
    AddOn1 { Variation = { Code = 1 }, Quantity = totalAmountOfQuantityForAddOnsWithCode = 1 }, 
    ... 
    AddOnX { Variation = { Code = X }, Quantity = totalAmountOfQuantityForAddOnsWithCode = X }, 
} 

È possibile utilizzare questo dotnetfiddle per testare dati fittizi.

Siamo spiacenti per il post lungo e apprezzerò qualsiasi aiuto. Ricorda anche che il mio C# e la conoscenza di Linq sono limitati.

+0

Giusto per chiarire, si vuole raccogliere i AddOns da ogni abbonamento in un unico set e poi gruppo che master impostata da Variation.Code? – ryanyuyu

+0

@ryanyuyu Sì, e per essere più specifici. Diciamo che ho un abbonamento con 20 add on con i codici 1, 2, 3. Voglio un abbonamento con 3 add on e la quantità totale di ciascuno con lo stesso codice. –

+0

Ok solo per essere sicuri, non vuoi combinare le cose tra diversi abbonamenti giusto? Quindi se hai 2 abbonamenti ciascuno con 10 add-on, vuoi due gruppi di add-on completamente separati e non un gruppo dal 20? – ryanyuyu

risposta

5

Se ho capito bene, quanto segue potrebbe produrre il risultato desiderato

var result = acc.Subscriptions.Select(s => new 
{ 
    Subscription = s, 
    AddOns = s.AddOns.SelectMany(a => a.Variations, (a, v) => new { a, v }) 
     .GroupBy(e => e.v.Code, (key, elements) => new 
     { 
      Code = key, 
      Quantity = elements.Sum(e => e.a.Quantity) 
     }).ToList() 
}).ToList(); 
+0

Grazie mille. Farò funzionare i miei test e lo accetterò :) –

2

Anche se non sono del tutto sicuro che questo è ciò che si vuole, provare questo

var codes = addOns.SelectMany(a => a.Variations).Select(v => v.Code).Distinct(); 

var addOnsByCode = new List<AddOn>(); //your desired result 
foreach (var code in codes) 
{ 
    var addOnsWithThisCode = addOns.Where(a => a.Variations.Any(v => v.Code == code)); 
    addOnsByCode.Add(new AddOn{ 
     Variations = new List<Variation> { new Variation { Code = code } }, 
     Quantity = addOnsWithThisCode.Sum(a => a.Quantity), 
     ID = string.Join("_", addOnsWithThisCode.Select(a => a.ID)) //not required> 
    }); 
} 

Dove addOns è un List<AddOn> , ad esempio

var addOns = new List<AddOn> { 
    new AddOn { 
     ID = "1", 
     Quantity = 5, 
     Variations = new List<Variation> 
     { 
      new Variation { Code = "A" }, 
      new Variation { Code = "B" } 
     } 
    }, 
    new AddOn { 
     ID = "2", 
     Quantity = 7, 
     Variations = new List<Variation> 
     { 
      new Variation { Code = "B" }, 
      new Variation { Code = "C" } 
     } 
    }, 
    new AddOn { 
     ID = "3", 
     Quantity = 9, 
     Variations = new List<Variation> 
     { 
      new Variation { Code = "D" }, 
      new Variation { Code = "A" } 
     } 
    }, 
}; 
+0

Grazie mille per la tua risposta e il tuo impegno, ma andrò con @IvanStoev. –

+1

Certo, l'approccio che risolve il problema è il migliore. –

2

Se si sottosta od il tuo problema correttamente penso che il seguente metodo ti aiuterà. Ho aggiunto un metodo all'interno della classe Subscription per raggruppare i suoi componenti aggiuntivi con i relativi codici di variazione e quindi sommare le quantità dei vari codici. La chiave del mio codice utilizza SelectMany per interrompere un singolo componente aggiuntivo con più varianti in elementi separati che accoppiano codice e quantità. Quindi puoi raggruppare gli elementi suddivisi.

public Dictionary<string, int> GetAddonGroups() 
{ 
    //spreading out each Add-on into multiple elements, each with a Code and quantity 
    var addOnVariationsWithQuantity = this.AddOns 
     .SelectMany(ad => ad.Variations 
        .Select(v => new {Code = v.Code, Quantity = ad.Quantity})); 

    //group by Code and Sum the quantity 
    var addOnGroups = addOnVariationsWithQuantity 
         .GroupBy(v => v.Code) 
         .ToDictionary(grp => grp.Key, 
             grp => grp.Sum(el => el.Quantity)); 
    return addOnGroups; 
} 

Forked Fiddle

+0

Grazie mille per la tua risposta e il tuo impegno, ma andrò con @IvanStoev. –

+1

@AlexChar nessun problema. Abbiamo finito per avere approcci simil-ish, con SelectMany. Sono solo contento che questo abbia aiutato un po '. – ryanyuyu