Raggruppa con più colonne usando lambda


122

Come posso raggruppare con più colonne usando lambda?

Ho visto esempi di come farlo usando linq to entity, ma sto cercando il modulo lambda.

Risposte:


252
var query = source.GroupBy(x => new { x.Column1, x.Column2 });

Funzionerebbe davvero? Penso che il test di uguaglianza per ogni oggetto in base al quale stai raggruppando fallirebbe poiché sono oggetti e non strutture.
Jacob il

@Aducci: grazie. Puoi esempio come posso ottenere IEnumerable degli elementi del gruppo?
Naor

6
@Jacob - I tipi anonimi sono classi immutabili con metodi GetHashCode& correttamente sovrascritti Equals. Sono stati progettati esattamente per questo tipo di caso d'uso.
Enigmativity

5
@Naor - GroupByrestituisce an IEnumerable<IGrouping<TKey, TSource>>che è essenzialmente an IEnumerable<IEnumerable<TSource>>con una Keyproprietà sull'enumerabile interno. Questo ti aiuta a ottenere "IEnumerable" degli elementi del gruppo?
Enigmativity

Se la mia variabile "sorgente" è una raccolta di dizionari, non funziona. Suggerimenti?
Joao Paulo

6

se il tuo tavolo è così

rowId     col1    col2    col3    col4
 1          a       e       12       2
 2          b       f       42       5
 3          a       e       32       2
 4          b       f       44       5


var grouped = myTable.AsEnumerable().GroupBy(r=> new {pp1 =  r.Field<int>("col1"), pp2 = r.Field<int>("col2")});

6
È molto importante notare che AsEnumerable porterà l'intera tabella in memoria prima di raggrupparla. Questo è decisamente importante su alcuni tavoli. Vedi questa risposta per maggiori informazioni: stackoverflow.com/questions/17968469/…
Brandon Barkley

4

Oltre alla risposta di aduchis sopra, se è necessario filtrare in base a quei gruppi per chiavi, è possibile definire una classe per racchiudere le molte chiavi.

return customers.GroupBy(a => new CustomerGroupingKey(a.Country, a.Gender))
                .Where(a => a.Key.Country == "Ireland" && a.Key.Gender == "M")
                .SelectMany(a => a)
                .ToList();

Dove CustomerGroupingKey prende le chiavi di gruppo:

    private class CustomerGroupingKey
    {
        public CustomerGroupingKey(string country, string gender)
        {
            Country = country;
            Gender = gender;
        }

        public string Country { get; }

        public string Gender { get; }
    }

1
Probabilmente farà risparmiare tempo a qualcuno: è meglio usare costruzioni predefinite con inizializzatori di oggetti. L'approccio nel codice di esempio sopra non verrà trattato bene da ORM come EF Core.
Konstantin

2
     class Element
        {
            public string Company;        
            public string TypeOfInvestment;
            public decimal Worth;
        }

   class Program
    {
        static void Main(string[] args)
        {
         List<Element> elements = new List<Element>()
            {
                new Element { Company = "JPMORGAN CHASE",TypeOfInvestment = "Stocks", Worth = 96983 },
                new Element { Company = "AMER TOWER CORP",TypeOfInvestment = "Securities", Worth = 17141 },
                new Element { Company = "ORACLE CORP",TypeOfInvestment = "Assets", Worth = 59372 },
                new Element { Company = "PEPSICO INC",TypeOfInvestment = "Assets", Worth = 26516 },
                new Element { Company = "PROCTER & GAMBL",TypeOfInvestment = "Stocks", Worth = 387050 },
                new Element { Company = "QUASLCOMM INC",TypeOfInvestment = "Bonds", Worth = 196811 },
                new Element { Company = "UTD TECHS CORP",TypeOfInvestment = "Bonds", Worth = 257429 },
                new Element { Company = "WELLS FARGO-NEW",TypeOfInvestment = "Bank Account", Worth = 106600 },
                new Element { Company = "FEDEX CORP",TypeOfInvestment = "Stocks", Worth = 103955 },
                new Element { Company = "CVS CAREMARK CP",TypeOfInvestment = "Securities", Worth = 171048 },
            };

            //Group by on multiple column in LINQ (Query Method)
            var query = from e in elements
                        group e by new{e.TypeOfInvestment,e.Company} into eg
                        select new {eg.Key.TypeOfInvestment, eg.Key.Company, Points = eg.Sum(rl => rl.Worth)};



            foreach (var item in query)
            {
                Console.WriteLine(item.TypeOfInvestment.PadRight(20) + " " + item.Points.ToString());
            }


            //Group by on multiple column in LINQ (Lambda Method)
            var CompanyDetails =elements.GroupBy(s => new { s.Company, s.TypeOfInvestment})
                               .Select(g =>
                                            new
                                            {
                                                company = g.Key.Company,
                                                TypeOfInvestment = g.Key.TypeOfInvestment,            
                                                Balance = g.Sum(x => Math.Round(Convert.ToDecimal(x.Worth), 2)),
                                            }
                                      );
            foreach (var item in CompanyDetails)
            {
                Console.WriteLine(item.TypeOfInvestment.PadRight(20) + " " + item.Balance.ToString());
            }
            Console.ReadLine();

        }
    }

1

Sono venuto fuori con un mix di definizione di una classe come la risposta di David, ma non richiedendo una classe Where per accompagnarla. Sembra qualcosa di simile:

var resultsGroupings = resultsRecords.GroupBy(r => new { r.IdObj1, r.IdObj2, r.IdObj3})
                                    .Select(r => new ResultGrouping {
                                        IdObj1= r.Key.IdObj1,
                                        IdObj2= r.Key.IdObj2,
                                        IdObj3= r.Key.IdObj3,
                                        Results = r.ToArray(),
                                        Count = r.Count()
                                    });



private class ResultGrouping
        {
            public short IdObj1{ get; set; }
            public short IdObj2{ get; set; }
            public int IdObj3{ get; set; }

            public ResultCsvImport[] Results { get; set; }
            public int Count { get; set; }
        }

Dov'è la resultRecordsmia lista iniziale che sto raggruppando, ed è un file List<ResultCsvImport>. Nota che l'idea qui è che, sto raggruppando per 3 colonne, IdObj1 e IdObj2 e IdObj3

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.