Bagikan melalui


klausul grup (Referensi C#)

Klausa group mengembalikan urutan IGrouping<TKey,TElement> objek. Urutan berisi nol atau lebih item yang cocok dengan nilai kunci untuk grup. Misalnya, Anda dapat mengelompokkan serangkaian string menurut huruf pertama di setiap string. Dalam hal ini, huruf pertama adalah kunci dan memiliki karakter jenis. Setiap IGrouping<TKey,TElement> objek menyimpan kunci ini di propertinya Key . Kompilator menyimpulkan jenis kunci.

Referensi bahasa C# mendokumentasikan versi bahasa C# yang paling baru dirilis. Ini juga berisi dokumentasi awal untuk fitur dalam pratinjau publik untuk rilis bahasa yang akan datang.

Dokumentasi mengidentifikasi fitur apa pun yang pertama kali diperkenalkan dalam tiga versi terakhir bahasa atau dalam pratinjau publik saat ini.

Petunjuk / Saran

Untuk menemukan kapan fitur pertama kali diperkenalkan di C#, lihat artikel tentang riwayat versi bahasa C#.

Anda dapat mengakhiri ekspresi kueri dengan klausul group, seperti yang ditunjukkan dalam contoh berikut:

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

Jika Anda ingin melakukan operasi kueri tambahan pada setiap grup, tentukan pengidentifikasi sementara dengan menggunakan ke dalam kata kunci kontekstual. Saat Anda menggunakan into, Anda harus melanjutkan kueri, dan akhirnya mengakhirinya dengan pernyataan select atau klausul group lainnya, seperti yang ditunjukkan dalam kutipan berikut:

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

Contoh penggunaan group dengan dan tanpa into yang lebih lengkap tersedia di bagian Contoh artikel ini.

Menghitung satu per satu hasil kueri grup

IGrouping<TKey,TElement> Karena objek yang group dihasilkan kueri pada dasarnya adalah daftar daftar, Anda harus menggunakan perulangan foreach berlapis untuk mengakses item di setiap grup. Loop luar berulang di atas kunci grup, dan loop dalam berulang di atas setiap item dalam grup itu sendiri. Grup dapat memiliki kunci tetapi tidak ada elemen. Perulangan berikut foreach menjalankan kueri dalam contoh kode sebelumnya:

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

Jenis kunci

Kunci grup dapat berupa jenis apa pun, seperti string, jenis numerik bawaan, atau jenis bernama yang ditentukan pengguna atau jenis anonim.

Pengelompokan berdasarkan string

Contoh kode sebelumnya menggunakan char. Anda juga dapat menentukan kunci string, seperti nama belakang lengkap:

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

Pengelompokan menurut bool

Contoh berikut menggunakan nilai bool untuk kunci untuk membagi hasil menjadi dua grup. Nilai berasal dari sub-ekspresi dalam group klausa.

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
*/

Pengelompokan berdasarkan rentang numerik

Contoh berikutnya menggunakan ekspresi untuk membuat kunci grup numerik yang mewakili rentang persentil. Ini menggunakan let untuk menyimpan hasil panggilan metode, sehingga Anda tidak perlu memanggil metode dua kali dalam group klausa. Untuk informasi selengkapnya tentang cara aman menggunakan metode dalam ekspresi kueri, lihat Menangani pengecualian dalam ekspresi kueri .

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
 */

Pengelompokan berdasarkan kunci komposit

Gunakan kunci komposit saat Anda ingin mengelompokkan elemen dengan lebih dari satu kunci. Buat kunci komposit dengan menggunakan jenis anonim atau jenis bernama untuk menahan elemen kunci. Dalam contoh berikut, asumsikan bahwa kelas Person memiliki anggota bernama surname dan city. Klausa ini group membuat grup terpisah untuk setiap set orang dengan nama belakang yang sama dan kota yang sama.

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

Gunakan jenis bernama jika Anda perlu meneruskan variabel kueri ke metode lain. Buat kelas khusus dengan properti yang diimplementasikan secara otomatis untuk kunci, lalu ambil alih Equals metode dan GetHashCode . Anda juga dapat menggunakan struct, yang tidak secara ketat memerlukan penimpaan metode tersebut. Untuk informasi selengkapnya, lihat Cara menerapkan kelas ringan dengan properti yang diterapkan secara otomatis dan Cara mengkueri file duplikat di pohon direktori. Artikel terakhir memiliki contoh kode yang menunjukkan cara menggunakan kunci komposit dengan jenis bernama.

Examples

Contoh berikut menunjukkan pola standar untuk mengurutkan data sumber ke dalam grup saat Anda tidak menerapkan logika kueri tambahan ke grup. Pola ini disebut pengelompokan tanpa kelanjutan. Contoh mengelompokkan elemen dalam array string sesuai dengan huruf pertamanya. Hasil kueri adalah jenis IGrouping<TKey,TElement> yang berisi properti Key publik jenis char dan koleksi IEnumerable<T> yang berisi setiap item dalam pengelompokan.

Hasil dari klausul group adalah serangkai dari suatu rangkaian. Untuk mengakses elemen individual dalam setiap grup yang dikembalikan, gunakan perulangan berlapis foreach di dalam perulangan yang mengulangi kunci grup, seperti yang ditunjukkan dalam contoh berikut.

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
     */

Contoh berikut menunjukkan cara melakukan logika tambahan pada grup setelah Anda membuatnya, dengan menggunakan kelanjutan dengan into. Untuk informasi selengkapnya, lihat into . Contoh berikut meminta setiap grup untuk memilih hanya grup yang nilai kuncinya adalah vokal.

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
*/

Pada waktu kompilasi, pengkompilasi menerjemahkan group klausul ke dalam panggilan ke GroupBy metode .

Sintaks group kueri klausa tidak mendukung perbandingan kesetaraan kustom. Jika Anda ingin menggunakan IEqualityComparer dalam kueri Anda, gunakan metode secara GroupBy eksplisit.

Lihat juga