LINQ Grouping Operators (GroupBy , into)

2022. 2. 7. 00:00CSharp/Advance

반응형

GroupBy 및 into 연산자는 연산 결과값을 group 화 하여 특정 변수에 저장한다.

 

기본사용

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };


// 각 item 을 5로 나눈 나머지를  g 그룹에 할당
var numberGroups = from n in numbers
                   group n by n % 5 into g
                   select (Remainder: g.Key, Numbers: g);

foreach (var g in numberGroups)
{
    Console.WriteLine($"Numbers with a remainder of {g.Remainder} when divided by 5:");
    foreach (var n in g.Numbers)
    {
        Console.WriteLine(n);
    }
}

// output
Numbers with a remainder of 0 when divided by 5:
5
0
Numbers with a remainder of 4 when divided by 5:
4
9
Numbers with a remainder of 1 when divided by 5:
1
6
Numbers with a remainder of 3 when divided by 5:
3
8
Numbers with a remainder of 2 when divided by 5:
7
2

 

그룹화 방법

// 제일 앞자리를 key로 그룹화
string[] words = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese" };

var wordGroups = from w in words
                 group w by w[0] into g
                 select (FirstLetter: g.Key, Words: g);

foreach (var g in wordGroups)
{
    Console.WriteLine("Words that start with the letter '{0}':", g.FirstLetter);
    foreach (var w in g.Words)
    {
        Console.WriteLine(w);
    }
}

// output
Words that start with the letter 'b':
blueberry
banana
Words that start with the letter 'c':
chimpanzee
cheese
Words that start with the letter 'a':
abacus
apple

 

// 속성을 key로 그룹화
List<Product> products = GetProductList();

// 속성을 key로 그룹화
var orderGroups = from p in products
                  group p by p.Category into g
                  select (Category: g.Key, Products: g);

foreach (var orderGroup in orderGroups)
{
    Console.WriteLine($"Products in {orderGroup.Category} category:");
    foreach (var product in orderGroup.Products)
    {
        Console.WriteLine($"\t{product}");
    }
}

// output
Products in Beverages category:
        ProductID=1 ProductName=Chai Category=Beverages UnitPrice=$18.00 UnitsInStock=39
        ProductID=2 ProductName=Chang Category=Beverages UnitPrice=$19.00 UnitsInStock=17
        ...
        ProductID=76 ProductName=Lakkalikoori Category=Beverages UnitPrice=$18.00 UnitsInStock=57
Products in Condiments category:
        ProductID=3 ProductName=Aniseed Syrup Category=Condiments UnitPrice=$10.00 UnitsInStock=13
        ProductID=4 ProductName=Chef Anton's Cajun Seasoning Category=Condiments UnitPrice=$22.00 UnitsInStock=53
        ...
        ProductID=77 ProductName=Original Frankfurter grune Soße Category=Condiments UnitPrice=$13.00 UnitsInStock=32
Products in Produce category:
        ProductID=7 ProductName=Uncle Bob's Organic Dried Pears Category=Produce UnitPrice=$30.00 UnitsInStock=15
        ProductID=14 ProductName=Tofu Category=Produce UnitPrice=$23.25 UnitsInStock=35
        ...
        ProductID=74 ProductName=Longlife Tofu Category=Produce UnitPrice=$10.00 UnitsInStock=4
Products in Meat/Poultry category:
        ProductID=9 ProductName=Mishi Kobe Niku Category=Meat/Poultry UnitPrice=$97.00 UnitsInStock=29
        ProductID=17 ProductName=Alice Mutton Category=Meat/Poultry UnitPrice=$39.00 UnitsInStock=0
        ...
        ProductID=55 ProductName=Pate chinois Category=Meat/Poultry UnitPrice=$24.00 UnitsInStock=115
Products in Seafood category:
        ProductID=10 ProductName=Ikura Category=Seafood UnitPrice=$31.00 UnitsInStock=31
        ProductID=13 ProductName=Konbu Category=Seafood UnitPrice=$6.00 UnitsInStock=24
        ...
        ProductID=73 ProductName=Rod Kaviar Category=Seafood UnitPrice=$15.00 UnitsInStock=101
Products in Dairy Products category:
        ProductID=11 ProductName=Queso Cabrales Category=Dairy Products UnitPrice=$21.00 UnitsInStock=22
        ProductID=12 ProductName=Queso Manchego La Pastora Category=Dairy Products UnitPrice=$38.00 UnitsInStock=86
        ...
        ProductID=72 ProductName=Mozzarella di Giovanni Category=Dairy Products UnitPrice=$34.80 UnitsInStock=14
Products in Confections category:
        ProductID=16 ProductName=Pavlova Category=Confections UnitPrice=$17.45 UnitsInStock=29
        ProductID=19 ProductName=Teatime Chocolate Biscuits Category=Confections UnitPrice=$9.20 UnitsInStock=25
        ...
        ProductID=68 ProductName=Scottish Longbreads Category=Confections UnitPrice=$12.50 UnitsInStock=6
Products in Grains/Cereals category:
        ProductID=22 ProductName=Gustaf's Knackebrod Category=Grains/Cereals UnitPrice=$21.00 UnitsInStock=104
        ProductID=23 ProductName=Tunnbrod Category=Grains/Cereals UnitPrice=$9.00 UnitsInStock=61
        ...
        ProductID=64 ProductName=Wimmers gute Semmelknodel Category=Grains/Cereals UnitPrice=$33.25 UnitsInStock=22

 

 

중첩 그룹

Order 를 Year 별로  Grouping 한 후 다시 그 안에서 Month 별로 Grouping 하는 예제

List<Customer> customers = GetCustomerList();

var customerOrderGroups = from c in customers
                          select
                          (
                          c.CompanyName,
                          YearGroups: from o in c.Orders
                                      group o by o.OrderDate.Year into yg
                                      select
                                      (
                                      Year: yg.Key,
                                      MonthGroups: from o in yg
                                                   group o by o.OrderDate.Month into mg
                                                   select (Month: mg.Key, Orders: mg)
                                      )
                          );

foreach (var ordersByCustomer in customerOrderGroups)
{
    Console.WriteLine($"Customer Name: {ordersByCustomer.CompanyName}");
    foreach (var ordersByYear in ordersByCustomer.YearGroups)
    {
        Console.WriteLine($"\tYear: {ordersByYear.Year}");
        foreach (var ordersByMonth in ordersByYear.MonthGroups)
        {
            Console.WriteLine($"\t\tMonth: {ordersByMonth.Month}");
            foreach (var order in ordersByMonth.Orders)
            {
                Console.WriteLine($"\t\t\tOrder: {order}");
            }
        }
    }
}


// output
Customer Name: Wilman Kala
        Year: 1996
                Month: 7
                        Order: 10248: 1996-07-04 for \440.00
        Year: 1997
                Month: 7
                        Order: 10615: 1997-07-30 for \120.00
                Month: 9
                        Order: 10673: 1997-09-18 for \412.35
                Month: 10
                        Order: 10695: 1997-10-07 for \642.00
        Year: 1998
                Month: 2
                        Order: 10873: 1998-02-06 for \336.80
                        Order: 10879: 1998-02-10 for \611.30
                        Order: 10910: 1998-02-26 for \452.90
                Month: 4
                        Order: 11005: 1998-04-07 for \586.00
Customer Name: Wolski Zajazd
        Year: 1996
                Month: 12
                        Order: 10374: 1996-12-05 for \459.00
        Year: 1997
                Month: 7
                        Order: 10611: 1997-07-25 for \808.00
                Month: 12
                        Order: 10792: 1997-12-23 for \399.85
        Year: 1998
                Month: 2
                        Order: 10870: 1998-02-04 for \160.00
                        Order: 10906: 1998-02-25 for \427.50
                Month: 4
                        Order: 10998: 1998-04-03 for \686.00
                        Order: 11044: 1998-04-23 for \591.60

사용자 지정 비교자를 사용하여 그룹핑

string[] anagrams = { "from   ", " salt", " earn ", "  last   ", " near ", " form  " };
var orderGroups = anagrams.GroupBy(w => w.Trim(), new AnagramEqualityComparer());
foreach (var set in orderGroups)
{
    // The key would be the first item in the set
    foreach (var word in set)
    {
        Console.WriteLine(word);
    }
    Console.WriteLine("...");
}

// 문자의 순서에 상관 없이 같은지 비교 (fo == of)
#region anagram-comparer
public class AnagramEqualityComparer : IEqualityComparer<string>
{
    public bool Equals(string x, string y) => getCanonicalString(x) == getCanonicalString(y);

    public int GetHashCode(string obj) => getCanonicalString(obj).GetHashCode();

    private string getCanonicalString(string word)
        {
            char[] wordChars = word.ToCharArray();
            Array.Sort<char>(wordChars);
            return new string(wordChars);
        }
}
#endregion

// output
from
 form
...
 salt
  last
...
 earn
 near
...

 

관련영상

https://youtu.be/tiDRR-D9LJQ

 

반응형