Pengurutan dan Pengelompokan

Pengurutan dengan OrderBy dan pengelompokan dengan Group By dan Into.

Daftar isi

Hasil query dapat diurutkan menurut satu atau beberapa kunci, dan dapat dirangkum menjadi kelompok beserta agregatnya. Topik ini membahas klausa Order By dengan arah Ascending dan Descending, metode OrderBy, OrderByDescending, dan ThenBy, serta Group By ... Into dengan agregat Group, Count(), dan Average() beserta cara menelusuri hasilnya. Daftar NilaiUjian yang digunakan di sepanjang modul ini kembali menjadi data contohnya.

Order By dalam sintaks query#

Order By menata ulang elemen hasil query menurut satu atau beberapa kunci. Arah Descending mengurutkan nilai dari terbesar ke terkecil, sedangkan Ascending dari terkecil ke terbesar, dan Ascending berlaku secara bawaan bila arah tidak dituliskan. Kunci kedua dan seterusnya dipisahkan tanda koma dan hanya menentukan urutan bila nilai kunci di depannya sama.

Program utama topik ini mencontohkan kedua bahasan sekaligus. Separuh pertama mengurutkan sembilan siswa menurut skor menurun dengan nama menaik sebagai pemecah nilai kembar, sedangkan separuh kedua mengelompokkan siswa menurut predikat.

vb Program.vb
Module Program

    Class NilaiUjian
        Public Property Nama As String
        Public Property Skor As Integer
    End Class

    Sub Main()
        Dim nilai As New List(Of NilaiUjian) From {
            New NilaiUjian With {.Nama = "Ali", .Skor = 88},
            New NilaiUjian With {.Nama = "Budi", .Skor = 72},
            New NilaiUjian With {.Nama = "Citra", .Skor = 95},
            New NilaiUjian With {.Nama = "Dewi", .Skor = 64},
            New NilaiUjian With {.Nama = "Eka", .Skor = 80},
            New NilaiUjian With {.Nama = "Fajar", .Skor = 58},
            New NilaiUjian With {.Nama = "Gita", .Skor = 90},
            New NilaiUjian With {.Nama = "Hana", .Skor = 76},
            New NilaiUjian With {.Nama = "Indra", .Skor = 88}
        }

        Dim urut = From n In nilai
                   Order By n.Skor Descending, n.Nama Ascending
                   Select n.Nama, n.Skor

        For Each baris In urut
            Console.WriteLine($"{baris.Nama}: {baris.Skor}")
        Next

        Console.WriteLine()

        Dim ringkasan = From n In nilai
                        Group By Predikat = If(n.Skor >= 80, "A", If(n.Skor >= 70, "B", "C"))
                        Into Jumlah = Count(), RataRata = Average(n.Skor)
                        Order By RataRata Descending
                        Select Predikat, Jumlah, RataRata

        For Each baris In ringkasan
            Console.WriteLine($"{baris.Predikat}: {baris.Jumlah} siswa, rata-rata {baris.RataRata:F2}")
        Next
    End Sub

End Module
text Keluaran
Citra: 95
Gita: 90
Ali: 88
Indra: 88
Eka: 80
Hana: 76
Budi: 72
Dewi: 64
Fajar: 58

A: 5 siswa, rata-rata 88.20
B: 2 siswa, rata-rata 74.00
C: 2 siswa, rata-rata 61.00

Skor Citra 95 dan Gita 90 menempati dua baris teratas, sedangkan Ali dan Indra sama-sama memperoleh skor 88 sehingga urutannya diputuskan oleh kunci kedua, yaitu nama menaik, dan Ali tampil lebih dulu. Klausa Select n.Nama, n.Skor membentuk tipe anonim yang membawa kedua nilai tersebut, sehingga baris.Nama dan baris.Skor dapat dibaca pada perulangan. Separuh kedua program menggunakan Group By dan diuraikan pada bagian Group By dan agregat Into.

Group By dan agregat Into#

Group By membagi elemen ke dalam kelompok menurut ekspresi kuncinya, lalu klausa Into menyatakan agregat yang dihitung untuk setiap kelompok. Baris hasilnya berupa tipe anonim yang berisi kunci beserta agregat-agregat tersebut, yaitu Predikat, Jumlah, dan RataRata pada program utama. Agregat Count() menghitung anggota kelompok, sedangkan Average(n.Skor), Sum(n.Skor), Min(n.Skor), dan Max(n.Skor) memproses satu ekspresi atas anggotanya.

Kunci Group By berupa ekspresi apa pun, dan program utama membentuknya dengan percabangan sebaris If menjadi huruf predikat A, B, atau C. Kelompok muncul mengikuti urutan kemunculan kuncinya pada data, kecuali Order By ditambahkan setelah Into, seperti Order By RataRata Descending yang menata kelompok berdasarkan rata-ratanya. Keluaran program memperlihatkan kelompok A berisi lima siswa dengan jumlah skor 441 sehingga rata-ratanya 88.20, diikuti kelompok B dengan dua siswa dan rata-rata 74.00, lalu kelompok C dengan dua siswa dan rata-rata 61.00.

Menelusuri isi kelompok dengan Group#

Agregat Group menyimpan anggota kelompok itu sendiri, sehingga isi setiap kelompok dapat ditelusuri satu per satu. Bentuknya Kelompok = Group pada klausa Into, dan hasil penelusurannya bertipe elemen asal, yaitu NilaiUjian. Diagram berikut menggambarkan pembagian sembilan siswa ke dalam tiga kelompok predikat.

nilaiAli 88Budi 72Citra 95Dewi 64Eka 80Fajar 58Gita 90Hana 76Indra 88Predikat A (5 siswa, rata-rata 88.20)Ali 88, Citra 95, Eka 80, Gita 90, Indra 88Predikat B (2 siswa, rata-rata 74.00)Budi 72, Hana 76Predikat C (2 siswa, rata-rata 61.00)Dewi 64, Fajar 58
Pembagian sembilan siswa ke dalam kelompok predikat

Program berikut mencetak setiap kelompok beserta anggotanya.

vb Contoh: menelusuri anggota setiap kelompok
Module DemoKelompok

    Class NilaiUjian
        Public Property Nama As String
        Public Property Skor As Integer
    End Class

    Sub Main()
        Dim nilai As New List(Of NilaiUjian) From {
            New NilaiUjian With {.Nama = "Ali", .Skor = 88},
            New NilaiUjian With {.Nama = "Budi", .Skor = 72},
            New NilaiUjian With {.Nama = "Citra", .Skor = 95},
            New NilaiUjian With {.Nama = "Dewi", .Skor = 64},
            New NilaiUjian With {.Nama = "Eka", .Skor = 80},
            New NilaiUjian With {.Nama = "Fajar", .Skor = 58},
            New NilaiUjian With {.Nama = "Gita", .Skor = 90},
            New NilaiUjian With {.Nama = "Hana", .Skor = 76},
            New NilaiUjian With {.Nama = "Indra", .Skor = 88}
        }

        Dim perPredikat = From n In nilai
                          Group By Predikat = If(n.Skor >= 80, "A", If(n.Skor >= 70, "B", "C"))
                          Into Kelompok = Group, Jumlah = Count()

        For Each baris In perPredikat
            Console.WriteLine($"Predikat {baris.Predikat} ({baris.Jumlah} siswa):")
            For Each n As NilaiUjian In baris.Kelompok
                Console.WriteLine($"  {n.Nama}: {n.Skor}")
            Next
        Next
    End Sub

End Module
text Keluaran
Predikat A (5 siswa):
  Ali: 88
  Citra: 95
  Eka: 80
  Gita: 90
  Indra: 88
Predikat B (2 siswa):
  Budi: 72
  Hana: 76
Predikat C (2 siswa):
  Dewi: 64
  Fajar: 58

Perulangan luar menampilkan kunci Predikat beserta agregat Jumlah, sedangkan perulangan dalam menelusuri baris.Kelompok dan membaca properti Nama serta Skor dari setiap anggotanya. Pola dua lapis ini digunakan ketika ringkasan saja tidak cukup, misalnya untuk mencetak daftar nilai per predikat.

Pengurutan dengan sintaks metode#

Sintaks metode menyediakan OrderBy dan OrderByDescending untuk kunci utama, lalu ThenBy dan ThenByDescending untuk kunci berikutnya. Program berikut menghasilkan urutan yang sama persis dengan query Order By n.Skor Descending, n.Nama Ascending pada bagian awal topik ini.

vb Contoh: OrderByDescending dan ThenBy
Module DemoUrutMetode

    Class NilaiUjian
        Public Property Nama As String
        Public Property Skor As Integer
    End Class

    Sub Main()
        Dim nilai As New List(Of NilaiUjian) From {
            New NilaiUjian With {.Nama = "Ali", .Skor = 88},
            New NilaiUjian With {.Nama = "Budi", .Skor = 72},
            New NilaiUjian With {.Nama = "Citra", .Skor = 95},
            New NilaiUjian With {.Nama = "Dewi", .Skor = 64},
            New NilaiUjian With {.Nama = "Eka", .Skor = 80},
            New NilaiUjian With {.Nama = "Fajar", .Skor = 58},
            New NilaiUjian With {.Nama = "Gita", .Skor = 90},
            New NilaiUjian With {.Nama = "Hana", .Skor = 76},
            New NilaiUjian With {.Nama = "Indra", .Skor = 88}
        }

        Dim urut = nilai.OrderByDescending(Function(n) n.Skor).ThenBy(Function(n) n.Nama)

        For Each n In urut
            Console.WriteLine($"{n.Nama}: {n.Skor}")
        Next
    End Sub

End Module
text Keluaran
Citra: 95
Gita: 90
Ali: 88
Indra: 88
Eka: 80
Hana: 76
Budi: 72
Dewi: 64
Fajar: 58

Rantai metodenya dibaca dari kiri ke kanan, yaitu kunci utama terlebih dahulu, lalu kunci pemecahnya. Metode-metode ini dipanggil pada koleksi apa pun tanpa menulis query, sehingga praktis untuk menata deretan hasil penyaringan tanpa menulis ulang query-nya.

Kesalahan umum#

Tiga kesalahan berikut berkait dengan sifat hasil pengurutan dan pengelompokan. Ketiganya terdeteksi dengan cepat bila keluaran program dibaca dengan saksama.

  1. Mengira Order By mengurutkan koleksi asalnya. Klausa ini menghasilkan urutan baru, sehingga pemanggilannya tanpa menampung atau menelusuri hasilnya tidak meninggalkan efek apa pun pada daftar sumber. Gunakan List.Sort bila pengurutan di tempat memang diinginkan.
  2. Memperlakukan baris hasil Group By sebagai elemen asal. Setiap barisnya berupa tipe anonim berisi kunci dan agregat, sehingga akses seperti baris.Nama ditolak compiler. Isi kelompok diakses melalui agregat Kelompok = Group.
  3. Menggunakan nama agregat yang tidak dinyatakan pada Into. Baris hasil hanya memiliki kunci beserta agregat yang dinyatakan, sehingga penggunaan baris.Total ketika Into hanya menyatakan Jumlah ditolak compiler. Samakan nama yang dituliskan dengan yang dinyatakan pada Into.

Ringkasan#

  • Order By kunci Descending, kunci2 Ascending menata hasil query, dan kunci berikutnya berperan sebagai pemecah nilai kembar.
  • Group By kunci Into ... membentuk tipe anonim yang berisi kunci beserta agregat seperti Count() dan Average(n.Skor).
  • Agregat Kelompok = Group menyimpan anggota kelompok, sehingga isi setiap kelompok dapat ditelusuri kembali.
  • OrderByDescending dan ThenBy menawarkan perilaku yang sama pada sintaks metode untuk koleksi mana pun.

Referensi#