다음을 통해 공유


group 절(C# 참조)

이 절은 group 개체 시 IGrouping<TKey,TElement> 퀀스를 반환합니다. 시퀀스에는 그룹의 키 값과 일치하는 항목이 0개 이상 포함됩니다. 예를 들어 각 문자열의 첫 번째 문자에 따라 문자열 시퀀스를 그룹화할 수 있습니다. 이 경우 첫 번째 문자는 키이며 형식 문자가 있습니다. 각 IGrouping<TKey,TElement> 개체는 이 키를 해당 속성에 저장합니다 Key . 컴파일러는 키의 형식을 유추합니다.

C# 언어 참조는 가장 최근에 릴리스된 C# 언어 버전을 문서화합니다. 또한 예정된 언어 릴리스의 공개 미리 보기 기능에 대한 초기 설명서도 포함되어 있습니다.

설명서는 언어의 마지막 세 버전 또는 현재 공개 미리 보기에서 처음 도입된 기능을 식별합니다.

팁 (조언)

C#에서 기능이 처음 도입된 시기를 찾으려면 C# 언어 버전 기록에 대한 문서를 참조하세요.

다음 예제와 같이 쿼리 식을 group 절로 끝낼 수 있습니다.

// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery1 =
    from student in students
    group student by student.Last[0];

각 그룹에 대해 추가 쿼리 작업을 수행하려면 상황에 맞는 키워드 사용하여 임시 식별자를 지정합니다. into를 사용하는 경우 쿼리를 계속 진행하고, 다음 예제와 같이 궁극적으로 select 문이나 다른 group 절로 끝내야 합니다.

// Group students by the first letter of their last name
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery2 =
    from student in students
    group student by student.Last[0] into g
    orderby g.Key
    select g;

group를 포함 및 포함하지 않고 into을 사용하는 보다 자세한 예제는 이 문서의 예제 섹션에 제공됩니다.

그룹 쿼리의 결과 열거

IGrouping<TKey,TElement> 쿼리에서 group 생성하는 개체는 기본적으로 목록 목록이므로 중첩된 foreach 루프를 사용하여 각 그룹의 항목에 액세스해야 합니다. 외부 루프는 그룹 키를 반복하고, 내부 루프는 그룹 자체에 있는 각 항목을 반복합니다. 그룹에는 키가 있지만 요소는 있을 수 없습니다. 다음 foreach 루프는 이전 코드 예제에서 쿼리를 실행합니다.

// Iterate group items with a nested foreach. This IGrouping encapsulates
// a sequence of Student objects, and a Key of type char.
// For convenience, var can also be used in the foreach statement.
foreach (IGrouping<char, Student> studentGroup in studentQuery2)
{
     Console.WriteLine(studentGroup.Key);
     // Explicit type for student could also be used here.
     foreach (var student in studentGroup)
     {
         Console.WriteLine("   {0}, {1}", student.Last, student.First);
     }
 }

키 형식

그룹 키는 문자열, 기본 제공 숫자 형식, 사용자 정의 명명된 형식, 무명 형식 등 모든 형식일 수 있습니다.

문자열로 그룹화

앞의 코드 예제에서는 char를 사용했습니다. 전체 성과 같은 문자열 키를 지정할 수도 있습니다.

// Same as previous example except we use the entire last name as a key.
// Query variable is an IEnumerable<IGrouping<string, Student>>
var studentQuery3 =
    from student in students
    group student by student.Last;

부울로 그룹화

다음 예제에서는 키에 부울 값을 사용하여 결과를 두 그룹으로 나눕니다. 값은 절의 하위 식에서 group 가져옵니다.

class GroupSample1
{
    // The element type of the data source.
    public class Student
    {
        public required string First { get; init; }
        public required string Last { get; init; }
        public required int ID { get; init; }
        public required List<int> Scores;
    }

    public static List<Student> GetStudents()
    {
        // Use a collection initializer to create the data source. Note that each element
        //  in the list contains an inner sequence of scores.
        List<Student> students =
        [
           new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= [97, 72, 81, 60]},
           new Student {First="Claire", Last="O'Donnell", ID=112, Scores= [75, 84, 91, 39]},
           new Student {First="Sven", Last="Mortensen", ID=113, Scores= [99, 89, 91, 95]},
           new Student {First="Cesar", Last="Garcia", ID=114, Scores= [72, 81, 65, 84]},
           new Student {First="Debra", Last="Garcia", ID=115, Scores= [97, 89, 85, 82]}
        ];

        return students;
    }

    static void Main()
    {
        // Obtain the data source.
        List<Student> students = GetStudents();

        // Group by true or false.
        // Query variable is an IEnumerable<IGrouping<bool, Student>>
        var booleanGroupQuery =
            from student in students
            group student by student.Scores.Average() >= 80; //pass or fail!

        // Execute the query and access items in each group
        foreach (var studentGroup in booleanGroupQuery)
        {
            Console.WriteLine(studentGroup.Key == true ? "High averages" : "Low averages");
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
            }
        }
    }
}
/* Output:
  Low averages
   Omelchenko, Svetlana:77.5
   O'Donnell, Claire:72.25
   Garcia, Cesar:75.5
  High averages
   Mortensen, Sven:93.5
   Garcia, Debra:88.25
*/

숫자 범위로 그룹화

다음 예제에서는 식을 사용하여 백분위수 범위를 나타내는 숫자 그룹 키를 만듭니다. 메서드 호출 결과를 저장하는 데 사용 let 하므로 절에서 group 메서드를 두 번 호출할 필요가 없습니다. 쿼리 식에 메서드를 안전하게 사용하는 방법에 대한 자세한 내용은 쿼리 식의 예외 처리를 참조하세요.

class GroupSample2
{
    // The element type of the data source.
    public class Student
    {
        public required string First { get; init; }
        public required string Last { get; init; }
        public required int ID { get; init; }
        public required List<int> Scores;
    }

    public static List<Student> GetStudents()
    {
        // Use a collection initializer to create the data source. Note that each element
        //  in the list contains an inner sequence of scores.
        List<Student> students =
        [
           new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= [97, 72, 81, 60]},
           new Student {First="Claire", Last="O'Donnell", ID=112, Scores= [75, 84, 91, 39]},
           new Student {First="Sven", Last="Mortensen", ID=113, Scores= [99, 89, 91, 95]},
           new Student {First="Cesar", Last="Garcia", ID=114, Scores= [72, 81, 65, 84]},
           new Student {First="Debra", Last="Garcia", ID=115, Scores= [97, 89, 85, 82]}
        ];

        return students;
    }

    // This method groups students into percentile ranges based on their
    // grade average. The Average method returns a double, so to produce a whole
    // number it is necessary to cast to int before dividing by 10.
    static void Main()
    {
        // Obtain the data source.
        List<Student> students = GetStudents();

        // Write the query.
        var studentQuery =
            from student in students
            let avg = (int)student.Scores.Average()
            group student by (avg / 10) into g
            orderby g.Key
            select g;

        // Execute the query.
        foreach (var studentGroup in studentQuery)
        {
            int temp = studentGroup.Key * 10;
            Console.WriteLine($"Students with an average between {temp} and {temp + 10}");
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
            }
        }
    }
}
/* Output:
     Students with an average between 70 and 80
       Omelchenko, Svetlana:77.5
       O'Donnell, Claire:72.25
       Garcia, Cesar:75.5
     Students with an average between 80 and 90
       Garcia, Debra:88.25
     Students with an average between 90 and 100
       Mortensen, Sven:93.5
 */

복합 키로 그룹화

요소를 둘 이상의 키로 그룹화하려는 경우 복합 키를 사용합니다. 익명 형식 또는 명명된 형식을 사용하여 키 요소를 보유하여 복합 키를 만듭니다. 다음 예제에서는 클래스 Person 에 이름이 지정된 surname 멤버가 있다고 가정합니다 city. 이 절은 group 성 및 동일한 도시를 가진 각 사용자 집합에 대해 별도의 그룹을 만듭니다.

group person by new {name = person.surname, city = person.city};

쿼리 변수를 다른 메서드에 전달해야 하는 경우 명명된 형식을 사용합니다. 키에 대해 자동으로 구현된 속성을 사용하여 특수 클래스를 만든 다음, 해당 클래스와 GetHashCode 메서드를 재정의 Equals 합니다. 또한 이러한 메서드 재정의를 엄격하게 요구하지 않는 구조체를 사용할 수도 있습니다. 자세한 내용은 자동으로 구현된 속성을 사용하여 간단한 클래스를 구현하는 방법디렉터리 트리에서 중복 파일을 쿼리하는 방법을 참조하세요. 두 번째 문서에는 명명된 형식과 함께 복합 키를 사용하는 방법을 보여 주는 코드 예제가 있습니다.

예시

다음 예제에서는 그룹에 추가 쿼리 논리를 적용하지 않을 때 원본 데이터를 그룹으로 정렬하는 표준 패턴을 보여 줍니다. 이 패턴을 연속 없이 그룹화라고 합니다. 이 예제에서는 첫 번째 문자에 따라 문자열 배열의 요소를 그룹화합니다. 쿼리 결과는 그룹에 각 항목을 포함하는 공용 IGrouping<TKey,TElement> 속성 형식 Keychar 컬렉션을 포함하는 IEnumerable<T> 형식입니다.

group 절의 결과는 시퀀스의 시퀀스입니다. 반환된 각 그룹 내의 개별 요소에 액세스하려면 다음 예제와 같이 그룹 키를 반복하는 루프 내부에 중첩된 foreach 루프를 사용합니다.

class GroupExample1
{
    static void Main()
    {
        // Create a data source.
        string[] words = ["blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese"];

        // Create the query.
        var wordGroups =
            from w in words
            group w by w[0];

        // Execute the query.
        foreach (var wordGroup in wordGroups)
        {
            Console.WriteLine($"Words that start with the letter '{wordGroup.Key}':");
            foreach (var word in wordGroup)
            {
                Console.WriteLine(word);
            }
        }
    }
}
/* 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
     */

다음 예제에서는 그룹을 만든 후 연속 작업을 사용하여 그룹에 대해 추가 논리를 수행하는 방법을 보여 있습니다 into. 자세한 내용은 into를 참조하세요. 다음 예제에서는 각 그룹을 쿼리하여 키 값이 모음인 그룹만 선택합니다.

class GroupClauseExample2
{
    static void Main()
    {
        // Create the data source.
        string[] words2 = ["blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese", "elephant", "umbrella", "anteater"];

        // Create the query.
        var wordGroups2 =
            from w in words2
            group w by w[0] into grps
            where (grps.Key == 'a' || grps.Key == 'e' || grps.Key == 'i'
                   || grps.Key == 'o' || grps.Key == 'u')
            select grps;

        // Execute the query.
        foreach (var wordGroup in wordGroups2)
        {
            Console.WriteLine($"Groups that start with a vowel: {wordGroup.Key}");
            foreach (var word in wordGroup)
            {
                Console.WriteLine($"   {word}");
            }
        }
    }
}
/* Output:
    Groups that start with a vowel: a
        abacus
        apple
        anteater
    Groups that start with a vowel: e
        elephant
    Groups that start with a vowel: u
        umbrella
*/

컴파일 시 컴파일러는 절을 group 메서드 호출로 GroupBy 변환합니다.

절 쿼리 구문 group 은 사용자 지정 같음 비교자를 지원하지 않습니다. 쿼리에서 사용 IEqualityComparer 하려는 경우 메서드를 GroupBy 명시적으로 사용합니다.

참고 항목