C# LINQ GroupBy, Group by into

 

특정 분류에 따라서 데이터를 나누는 경우의 코드는 어떻게 작성하는가?

생각해 볼 수 있는 가장 쉬운 방법은 foreach를 돌려가면서 Dictionary에 분류별로 담는 것이다.

 

그런데 LINQ에는 입력된 데이터를 분류할 수 있는

Group by into 쿼리식 혹은 GroupBy 메서드 호출구문이 존재한다.

 

Group 쿼리식

Group은 쿼리식으로 사용되는 경우가 많은데,

분류까지만 하는 경우 group by 까지만 사용하고

분류된 것을 또다시 참조해서 쿼리식을 작성하는 경우 into까지 사용한다.

 

n을 그룹핑(group) 하는데, 기준(by)은 n.Class로 나누고, 이를 c에 담는다.(into)  
var results = from n in students
    group n by n.Class into c
    select new
    {
        Class = c.Key,
        Age = c.Count()
    };

 

 

GroupBy() 메서드 호출 구문 사용하기

메서드 호출 구문에서는 다음과 같이 사용한다.

넘겨줘야 되는 것은 keySelector라고 명명된  Func<TSource, TKey> 이다. (요소를 넣고 Key를 리턴하는 함수)

 

예시) 문자열에서 한 번만 등장한 문자열을 순서대로 정렬하여 리턴하기 

public string MyMethod(string s) {
    char[] charArray = s.ToCharArray()
                        .GroupBy(n => n)
                        .Where(n => n.Count() == 1)
                        .Select(n => n.Key)
                        .OrderBy(n => n).ToArray();
        
    return new string(charArray);
}

만약 GroupBy를 사용하지 않는다면, 별도로 Dictionary를 선언하여 나눠담는과정이 필요했을 것이다.

 

 

Select()를 혼합하여 GroupBy() 메서드 호출 구문 사용하기

요소의 인덱스 등이 필요한경우 미리 Select를 사용하여 무명형식으로 사용하는 방법도 있다.

 

예시) 배열이 있을 때, 요소를 10개씩 나누어 담는 경우 

static void Main()
{
    solution.Method(Enumerable.Range(0, 30).ToArray()); // 0 ~ 29 까지의 연속 숫자 Array
}

public void Method(int[] arg)
{
    var group = arg.Select((n, index) => new { n, index })
                    .GroupBy(n => n.index / 10); // 나누는 몫을 기준으로 그룹핑

    foreach (var item in group)
    {
        Console.WriteLine(item.Key);
        foreach(var sub in item)
            Console.WriteLine(sub);
    }
}

출력값은 다음과 같다.

지금은 요소가 index와 동일한 값을 가져서 굳이 Select로 익명 타입을 만들 필요가 없긴 했지만 

연속 숫자가 아닌 데이터였다면 인덱스 값도 유용하게 사용할 수 있다.

 

 

 

elementSelect 추가하기

GroupBy의 메서드구문 문서를 찾아보면 오버라이드로 elementSelect도 추가할 수 있다.

 

 

예시) A부터 30개의 유니코드 문자를 출력

static void Main()
{
    solution.Method(Enumerable.Range(0, 30).ToArray()); // 0 ~ 29 까지의 연속 숫자 Array
}

public void Method(int[] arg)
{
    var group = arg.Select((n, index) => new { n, index })
                .GroupBy(k => k.index / 10, k => (char)(65 + k.n));

    foreach (var item in group)
    {
        Console.WriteLine($"============{item.Key}=========================");
        foreach(var sub in item)
            Console.WriteLine(sub);
    }

    Console.WriteLine("end");
}

 

출력은 다음과 같다.

사실 그룹핑한다음에 Select를 추가로 붙이는 것과 다를 바 없어 보이긴 한다.

 

 

 

 

 

댓글

Designed by JB FACTORY