Laporan yang urutannya berubah-ubah sulit dibandingkan antar pemanggilan. Operator ordering menata elemen berdasarkan satu kunci primer dan, bila perlu, kunci sekunder. C# menyediakan empat operator untuk keperluan ini, dan urutan elemen berkunci sama tetap terjaga secara stabil.
Kunci Primer dan Kunci Sekunder #
Contoh berikut mengurutkan produk menurut kategori, lalu menurut harga dari yang terbesar:
record Produk(string Nama, string Kategori, int Harga, int Stok);
List<Produk> produk = new()
{
new Produk("Kopi Gayo", "Minuman", 25000, 40),
new Produk("Teh Melati", "Minuman", 15000, 60),
new Produk("Roti Bakar", "Makanan", 12000, 25),
new Produk("Susu UHT", "Minuman", 20000, 35),
new Produk("Keripik Singkong", "Makanan", 10000, 80)
};
var urut = produk
.OrderBy(p => p.Kategori)
.ThenByDescending(p => p.Harga);
foreach (var p in urut)
{
Console.WriteLine($"{p.Kategori}: {p.Nama} ({p.Harga})");
}Output yang Dihasilkan:
Makanan: Roti Bakar (12000)
Makanan: Keripik Singkong (10000)
Minuman: Kopi Gayo (25000)
Minuman: Susu UHT (20000)
Minuman: Teh Melati (15000)Mari kita bedah baris demi baris:
.OrderBy(p => p.Kategori): kunci primer; kategori disusun menaik secara alfabetis, sehinggaMakanantampil sebelumMinuman..ThenByDescending(p => p.Harga): kunci sekunder; di dalam kategori yang sama, harga terbesar tampil lebih dulu.- stabilitas urutan: produk dengan kunci sama tetap mempertahankan urutan asli sumbernya.
- padanan query expression: gabungan ini ditulis
orderby p.Kategori, p.Harga descendingdalam satu klausa.
Empat Operator Ordering #
| Operator | Arah | Peran |
|---|---|---|
OrderBy | menaik | kunci primer |
OrderByDescending | menurun | kunci primer |
ThenBy | menaik | kunci sekunder dan seterusnya |
ThenByDescending | menurun | kunci sekunder dan seterusnya |
Klausa ThenBy* hanya dipakai setelah OrderBy*, karena kunci sekunder bermakna bila kunci primer menghasilkan grup yang sama. Untuk membalik urutan hasil apa adanya tanpa memedulikan kunci, tersedia method Reverse().
Seluruh operator ordering juga menerima IComparer<T> sebagai argumen kedua, misalnya OrderBy(p => p.Nama, StringComparer.OrdinalIgnoreCase) untuk mengabaikan perbedaan huruf besar-kecil. Tanpa comparer khusus, perbandingan string mengikuti aturan bawaan tipe string, dan perilaku itu menentukan hasil antara nama yang berawalan huruf besar maupun kecil.
Setiap panggilan OrderBy* menelusuri seluruh sumber, sehingga pengurutan termasuk operator yang paling berat; bab LINQ Performance mengingatkan agar kita tidak memanggilnya tanpa kebutuhan.