จัดกลุ่มโดยมีหลายคอลัมน์โดยใช้ lambda


122

ฉันจะจัดกลุ่มโดยมีหลายคอลัมน์โดยใช้แลมบ์ดาได้อย่างไร

ฉันเห็นตัวอย่างวิธีการใช้ linq กับเอนทิตี แต่ฉันกำลังมองหาฟอร์มแลมบ์ดา

คำตอบ:


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

สิ่งนี้จะใช้งานได้จริงหรือไม่? ฉันคิดว่าการทดสอบความเท่าเทียมกันสำหรับแต่ละวัตถุที่คุณจัดกลุ่มจะล้มเหลวเนื่องจากเป็นวัตถุไม่ใช่โครงสร้าง
เจ

@Aducci: ขอบคุณ คุณสามารถยกตัวอย่างได้อย่างไรว่าฉันจะรับ IEnumerable ของรายการกลุ่มได้หรือไม่?
Naor

6
@Jacob - ประเภทที่ไม่ระบุตัวตนเป็นคลาสที่ไม่เปลี่ยนรูปโดยมีการเขียนทับGetHashCodeและEqualsวิธีการอย่างถูกต้อง พวกเขาที่ออกแบบมาสำหรับกรณีการใช้งานประเภทนี้
Enigmativity

5
@Naor - GroupByส่งคืนค่าIEnumerable<IGrouping<TKey, TSource>>ซึ่งโดยพื้นฐานแล้วIEnumerable<IEnumerable<TSource>>เป็นKeyคุณสมบัติที่ระบุได้ภายใน ช่วยให้คุณได้รับ "IEnumerable" ของรายการกลุ่มหรือไม่
Enigmativity

หากตัวแปร 'แหล่งที่มา' ของฉันเป็นคอลเล็กชันพจนานุกรมสิ่งนี้จะไม่ทำงาน ข้อเสนอแนะ?
Joao Paulo

6

ถ้าโต๊ะของคุณเป็นแบบนี้

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
เป็นสิ่งสำคัญมากที่จะต้องทราบว่า AsEnumerable จะนำตารางทั้งหมดเข้าสู่หน่วยความจำก่อนจัดกลุ่ม แน่นอนว่ามีความสำคัญกับบางตาราง ดูคำตอบสำหรับข้อมูลเชิงลึกเพิ่มเติม: stackoverflow.com/questions/17968469/…
Brandon Barkley

4

นอกเหนือจากคำตอบของaduchisด้านบน - หากคุณต้องการกรองตามกลุ่มเหล่านั้นด้วยคีย์คุณสามารถกำหนดคลาสเพื่อรวมคีย์ต่างๆได้

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

โดยที่ CustomerGroupingKey รับคีย์กลุ่ม:

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

        public string Country { get; }

        public string Gender { get; }
    }

1
อาจจะช่วยใครบางคนได้บ้าง: ควรใช้โครงสร้างเริ่มต้นกับวัตถุเริ่มต้น แนวทางในโค้ดตัวอย่างด้านบนจะไม่ได้รับการปฏิบัติโดย ORM เช่น 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

ฉันคิดแบบผสมผสานระหว่างการกำหนดชั้นเรียนเหมือนกับคำตอบของเดวิด แต่ไม่ต้องการให้ชั้นเรียนไปด้วย ดูเหมือนว่า:

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

resultRecordsรายการเริ่มต้นของฉันอยู่ที่ไหนฉันจัดกลุ่มและเป็นList<ResultCsvImport>ไฟล์. โปรดทราบว่าแนวคิดในที่นี้คือฉันจัดกลุ่มตาม 3 คอลัมน์ IdObj1 และ IdObj2 และ IdObj3

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.