C#/LINQ

[C#]LINQ 데이터 그룹화 - GroupBy 메서드

DevStory 2022. 8. 4.

GroupBy 메서드

C# Linq에서 제공되는 GroupBy() 메서드는 SQL에서 사용할 수 있는 Group By 절과 동일한 작업을 수행합니다. 즉, GroupBy() 메서드에 전달된 키(또는 프로퍼티)를 기준으로 데이터를 그룹화합니다.

 

주로 다음 예시처럼 합계, 최솟값, 최댓값, 평균, 개수를 구하기 위해 데이터를 그룹화합니다.

- 특정 연도의 매출

- 부서별 인원수

- 각 반별로 평균 점수 계산


예제에 사용되는 클래스

이번 포스팅에서 사용되는 Student 클래스입니다.

public class Student
{
  public string ID { get; set; } // 학생을 식별하는 키
  public string Name { get; set; } // 학생의 이름
  public int Grade { get; set; } // 학년
  public int Class { get; set; } // 반

  public static List<Student> GetStudents()
  {
    return new List<Student>() 
    {
      // 1학년 1반
      new Student { ID = "0001", Name = "Preety",   Grade = 1, Class = 1},
      new Student { ID = "0002", Name = "Snurag",   Grade = 1, Class = 1},
      // 1학년 2반
      new Student { ID = "0003", Name = "Pranaya",  Grade = 1, Class = 2},

      // 2학년 1반
      new Student { ID = "0004", Name = "Anurag",   Grade = 2, Class = 1},
      new Student { ID = "0005", Name = "Hina",     Grade = 2, Class = 1},
      // 2학년 2반
      new Student { ID = "0006", Name = "Priyanka", Grade = 2, Class = 2},

      // 3학년 1반
      new Student { ID = "0007", Name = "santosh",  Grade = 3, Class = 1},
      new Student { ID = "0008", Name = "Tina",     Grade = 3, Class = 1},
      // 3학년 2반
      new Student { ID = "0009", Name = "Celina",   Grade = 3, Class = 2},
      // 3학년 3반
      new Student { ID = "0010", Name = "Sambit",   Grade = 3, Class = 3}
    };
  }
}

예제 1. 학년별 인원수 - 질의 구문

학년별 인원수를 구하기 위해서는 Grdae(학년) 프로퍼티를 기준으로 그룹화하고 집계 함수의 Count() 메서드를 사용하여 인원수를 계산합니다.

class Program
{
  static void Main(string[] args)
  {
    var GroupByQueryResult = (from student in Student.GetStudents()
                              group student by student.Grade into groupData
                              select new
                              {
                                Grade = groupData.Key,
                                Count = groupData.Count()
                              });
                              
    Console.WriteLine("질의 구문");
    foreach (var group in GroupByQueryResult)
    {
      Console.WriteLine(group.Grade + "학년의 인원 수: " + group.Count);
    }
  }
}

[실행 결과]

질의 구문
1학년의 인원 수: 3
2학년의 인원 수: 3
3학년의 인원 수: 4

예제 2. 학년별 인원수 - 메서드 구문

다음 예제는 학년별 인원수를 메서드 구문으로 계산합니다.

class Program
{
  static void Main(string[] args)
  {
    var GroupByMethodResult = Student.GetStudents()
                .GroupBy(student => student.Grade)
                .Select(groupData => new
                {
                  Grade = groupData.Key,
                  Count = groupData.Count()
                });
                              
    Console.WriteLine("메서드 구문");
    foreach (var group in GroupByMethodResult)
    {
      Console.WriteLine(group.Grade + "학년의 인원 수: " + group.Count);
    }
  }
}

[실행 결과]

질의 구문
1학년의 인원 수: 3
2학년의 인원 수: 3
3학년의 인원 수: 4

예제 3. GroupBy와 정렬

GroupBy와 정렬을 같이 처리해야 하는 경우 정렬 기준에 따라 처리 순서가 다릅니다..

 

다음 예제는 Grade(학년) 프로퍼티를 기준으로 데이터를 내림차순으로 정렬 및 그룹화하고 Class(반) 프로퍼티를 내림차순으로 정렬합니다.

 

그룹화 및 정렬된 데이터에서 학년의 인원 수와 학생 정보를 콘솔에 출력합니다.

class Program
{
  static void Main(string[] args)
  {
    // 1. 질의 구문(Query Syntax)
    var GroupByQueryResult = (from student in Student.GetStudents()
                              group student by student.Grade into groupData
                              orderby groupData.Key descending
                              select new
                              {
                                Grade = groupData.Key,
                                Students  = groupData.OrderByDescending(item => item.Class)
                              });

    // 2. 메서드 구문(Method Syntax)
    var GroupByMethodResult = Student.GetStudents()
        .GroupBy(student => student.Grade)
        .OrderByDescending(groupData => groupData.Key)
        .Select(groupData => new
        {
          Grade = groupData.Key,
          Students = groupData.OrderByDescending(item => item.Class)
        });

    Console.WriteLine("질의 구문");
    foreach (var group in GroupByQueryResult)
    {
      Console.WriteLine(group.Grade + "학년의 인원 수: " + group.Students.Count());
      foreach (var student in group.Students)
      {
        Console.WriteLine(student.Grade + "학년 " + student.Class + "반 " + student.Name);
      }
      Console.WriteLine();
    }

    Console.WriteLine("\n메서드 구문");
    foreach (var group in GroupByMethodResult)
    {
      Console.WriteLine(group.Grade + "학년의 인원 수: " + group.Students.Count());
      foreach (var student in group.Students)
      {
        Console.WriteLine(student.Grade + "학년 " + student.Class + "반 " + student.Name);
      }
      Console.WriteLine();
    }
  }
}

[실행 결과]

질의 구문
3학년의 인원 수: 4
3학년 3반 Sambit
3학년 2반 Celina
3학년 1반 santosh
3학년 1반 Tina

2학년의 인원 수: 3
2학년 2반 Priyanka
2학년 1반 Anurag
2학년 1반 Hina

1학년의 인원 수: 3
1학년 2반 Pranaya
1학년 1반 Preety
1학년 1반 Snurag


메서드 구문
3학년의 인원 수: 4
3학년 3반 Sambit
3학년 2반 Celina
3학년 1반 santosh
3학년 1반 Tina

2학년의 인원 수: 3
2학년 2반 Priyanka
2학년 1반 Anurag
2학년 1반 Hina

1학년의 인원 수: 3
1학년 2반 Pranaya
1학년 1반 Preety
1학년 1반 Snurag

순서 1. Grade(학년) 프로퍼티를 기준으로 데이터 그룹화

순서 2. 데이터 그룹 기준인 Grade 프로퍼티를 내림차순으로 정렬

순서 3. select절에서 Class 프로퍼티를 내림차순으로 정렬


예제 4. 여러 필드를 기준으로 그룹화 - 질의 구문

데이터를 그룹화하는 기준이 여러 프로퍼티인 경우 질의 구문에서는 익명 타입으로 기준을 설정합니다.

 

다음 예제는 질의 구문으로 Grade(학년), Class(반) 기준으로 데이터를 그룹화하고 학년별 반의 총 학생 수를 구합니다.

class Program
{
  static void Main(string[] args)
  {
    var GroupByQueryResult = (from student in Student.GetStudents()
                              group student by new
                              {
                                student.Grade,
                                student.Class
                              } into groupData
                              select new
                              {
                                Grade = groupData.Key.Grade,
                                Class = groupData.Key.Class,
                                Count = groupData.Count()
                              });
                              
    Console.WriteLine("질의 구문");
    foreach (var group in GroupByQueryResult)
    {
      Console.WriteLine(group.Grade + "학년 " + group.Class + "반의 인원 수: " + group.Count);
    }
  }
}

[실행 결과]

질의 구문
1학년 1반의 인원 수: 2
1학년 2반의 인원 수: 1
2학년 1반의 인원 수: 2
2학년 2반의 인원 수: 1
3학년 1반의 인원 수: 2
3학년 2반의 인원 수: 1
3학년 3반의 인원 수: 1

예제 5. 여러 필드를 기준으로 그룹화 - 메서드 구문

메서드 구문에서 여러 필드를 기준으로 그룹화하는 경우 질의 구문과 마찬가지로 익명 타입으로 기준을 설정합니다.

 

다음 예제는 메서드 구문으로 Grade(학년), Class(반) 기준으로 데이터를 그룹화하고 학년별 반의 총 학생 수를 구합니다.

class Program
{
  static void Main(string[] args)
  {
    var GroupByMethodResult = Student.GetStudents()
        .GroupBy(student => new { student.Grade, student.Class })
        .Select(groupData => new
        {
          Grade = groupData.Key.Grade,
          Class = groupData.Key.Class,
          Count = groupData.Count()
        });

    Console.WriteLine("메서드 구문");
    foreach (var group in GroupByMethodResult)
    {
      Console.WriteLine(group.Grade + "학년 " + group.Class + "반의 인원 수: " + group.Count);
    }
  }
}

[실행 결과]

메서드 구문
1학년 1반의 인원 수: 2
1학년 2반의 인원 수: 1
2학년 1반의 인원 수: 2
2학년 2반의 인원 수: 1
3학년 1반의 인원 수: 2
3학년 2반의 인원 수: 1
3학년 3반의 인원 수: 1
반응형

댓글