klausul grup (Referensi C#)

Klausul group mengembalikan serangkaian objek IGrouping<TKey,TElement> yang 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 jenis char, dan disimpan di properti Key dari setiap objek IGrouping<TKey,TElement>. Kompilator menyimpulkan jenis kunci.

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, Anda dapat menentukan pengenal 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 hasil kueri grup

Karena objek IGrouping<TKey,TElement> yang dihasilkan dari kueri group pada dasarnya adalah daftar dari suatu daftar, Anda harus menggunakan loop foreach yang dikumpulkan 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 mungkin memiliki kunci tetapi tidak memiliki elemen. Berikut ini adalah foreach loop yang mengeksekusi 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. Kunci string dapat dengan mudah ditentukan sebagai gantinya, misalnya 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 menunjukkan penggunaan nilai bool untuk kunci untuk membagi hasil menjadi dua kelompok. Perhatikan bahwa nilai dihasilkan oleh sub-ekspresi dalam klausul 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
*/

Pengelompokan berdasarkan rentang numerik

Contoh berikutnya menggunakan ekspresi untuk membuat kunci grup numerik yang mewakili rentang persentil. Perhatikan penggunaan let sebagai lokasi yang nyaman untuk menyimpan hasil pemanggilan metode, sehingga Anda tidak perlu memanggil metode dua kali dalam klausul group. 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 {0} and {1}", temp, 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 bila Anda ingin mengelompokkan elemen menurut lebih dari satu kunci. Anda membuat kunci komposit dengan menggunakan jenis anonim atau jenis bernama untuk menahan elemen kunci. Dalam contoh berikut, asumsikan bahwa kelas Person telah dideklarasikan dengan anggota bernama surname dan city. Klausul group menyebabkan grup terpisah dibuat untuk setiap kumpulan 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 harus meneruskan variabel kueri ke metode lain. Buat kelas khusus menggunakan properti yang diterapkan secara otomatis untuk kunci, lalu timpa metode Equals dan GetHashCode. Anda juga dapat menggunakan struct, dalam hal ini Anda tidak harus benar-benar mengganti metode tersebut. Untuk informasi lebih lanjut, lihat Cara menerapkan kelas ringan dengan properti yang diterapkan secara otomatis dan Cara membuat kueri untuk file duplikat di pohon direktori . Artikel terakhir memiliki contoh kode yang menunjukkan cara menggunakan kunci komposit dengan jenis bernama.

Contoh 1

Contoh berikut menunjukkan pola standar untuk mengurutkan data sumber ke dalam grup saat tidak ada logika kueri tambahan yang diterapkan ke grup. Ini disebut pengelompokan tanpa kelanjutan. Elemen-elemen dalam array string dikelompokkan menurut huruf pertama mereka. 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. Oleh karena itu, untuk mengakses elemen individual dalam setiap grup yang dikembalikan, gunakan loop foreach bersarang di dalam loop 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 '{0}':", 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 2

Contoh ini menunjukkan cara melakukan logika tambahan pada grup setelah Anda membuatnya, dengan menggunakan lanjutan dengan into. Untuk informasi lebih lanjut, lihat ke . 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: {0}", wordGroup.Key);
            foreach (var word in wordGroup)
            {
                Console.WriteLine("   {0}", 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
*/

Keterangan

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

Lihat juga