Mit Lambda mit mehreren Spalten gruppieren

122

Wie kann ich mit Lambda nach mehreren Spalten gruppieren?

Ich habe Beispiele gesehen, wie man es mit linq für Entitäten macht, aber ich suche nach Lambda-Form.

Naor
quelle

Antworten:

252
var query = source.GroupBy(x => new { x.Column1, x.Column2 });
Aducci
quelle
Würde das tatsächlich funktionieren? Ich würde denken, dass der Gleichheitstest für jedes Objekt, nach dem Sie gruppieren, fehlschlagen würde, da es sich um Objekte und nicht um Strukturen handelt.
Jacob
@ Adcci: Danke. Können Sie ein Beispiel dafür geben, wie ich IEnumerable der Gruppenelemente erhalten kann?
Naor
6
@Jacob - Anonyme Typen sind unveränderliche Klassen mit ordnungsgemäß überschriebenen GetHashCode& EqualsMethoden. Sie wurden genau für diese Art von Anwendungsfall entwickelt.
Rätselhaftigkeit
5
@Naor - GroupBygibt ein zurück, IEnumerable<IGrouping<TKey, TSource>>das im Wesentlichen ein IEnumerable<IEnumerable<TSource>>mit einer KeyEigenschaft auf der inneren Aufzählung ist. Hilft Ihnen das, die "IEnumerable" der Gruppenelemente zu erhalten?
Rätselhaftigkeit
Wenn meine 'Quell'-Variable eine Wörterbuchsammlung ist, funktioniert dies nicht. Vorschläge?
Joao Paulo
6

wenn dein Tisch so ist

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")});
Jhankar Mahbub
quelle
6
Es ist sehr wichtig zu beachten, dass AsEnumerable die gesamte Tabelle vor dem Gruppieren in den Speicher bringt. Das ist auf einigen Tischen definitiv wichtig. Sehen Sie diese Antwort für mehr Einsicht: stackoverflow.com/questions/17968469/…
Brandon Barkley
4

Neben der obigen Antwort von Aduchis : Wenn Sie dann basierend auf dieser Gruppe nach Schlüsseln filtern müssen, können Sie eine Klasse definieren, um die vielen Schlüssel zu verpacken.

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

Wo CustomerGroupingKey die Gruppenschlüssel verwendet:

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

        public string Country { get; }

        public string Gender { get; }
    }
David McEleney
quelle
1
Wird wahrscheinlich jemandem Zeit sparen: Es ist besser, Standardkonstruktionen mit Objektinitialisierern zu verwenden. Der Ansatz im obigen Beispielcode wird von ORMs wie EF Core nicht gut behandelt.
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();

        }
    }
Sandeep Tripathi
quelle
1

Ich hatte eine Mischung aus der Definition einer Klasse wie Davids Antwort, aber ohne die Notwendigkeit einer Where-Klasse. Es sieht ungefähr so ​​aus:

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

Wo resultRecordsist meine anfängliche Liste, die ich gruppiere, und es ist eine List<ResultCsvImport>. Beachten Sie, dass die Idee hier ist, dass ich nach 3 Spalten gruppiere, IdObj1 und IdObj2 und IdObj3

Jeff Moretti
quelle