Langsung ke konten
KamusNgoding
Menengah Csharp 3 menit baca

Koleksi Data di C#: List, Dictionary, dan LINQ

#csharp #list #dictionary #koleksi #generics #linq #array

Hampir semua aplikasi nyata bekerja dengan kumpulan data: daftar produk, riwayat transaksi, atau mapping kode ke nama. C# menyediakan berbagai koleksi yang powerful dan type-safe melalui System.Collections.Generic. Di artikel ini kita akan mempelajari koleksi yang paling sering digunakan beserta pengenalan LINQ — cara elegan untuk memfilter dan mentransformasi data.

Array vs List

// Array: ukuran tetap, performa sedikit lebih baik
int[] nilai_array = { 85, 92, 78, 95, 88 };
nilai_array[0] = 90; // ✅ Ubah nilai
// nilai_array.Length = 10; // ❌ Ukuran tidak bisa diubah

// List<T>: ukuran dinamis, lebih fleksibel
List<int> nilai_list = new List<int> { 85, 92, 78, 95, 88 };
nilai_list.Add(91);       // Tambah elemen
nilai_list.Remove(78);    // Hapus nilai tertentu
nilai_list.RemoveAt(0);   // Hapus di indeks tertentu
Console.WriteLine(nilai_list.Count); // Jumlah elemen
// Output: 5

List — Koleksi Dinamis

List<string> kota = new List<string>();

// Menambahkan elemen
kota.Add("Jakarta");
kota.Add("Surabaya");
kota.Add("Bandung");
kota.AddRange(new[] { "Medan", "Makassar" }); // Tambah banyak sekaligus

// Akses dan iterasi
Console.WriteLine(kota[0]);         // Output: Jakarta
Console.WriteLine(kota.Count);      // Output: 5

foreach (string k in kota)
{
    Console.WriteLine($"- {k}");
}

// Pencarian
bool ada_bandung = kota.Contains("Bandung");
int indeks = kota.IndexOf("Surabaya");
Console.WriteLine($"Ada Bandung: {ada_bandung}, Indeks Surabaya: {indeks}");
// Output: Ada Bandung: True, Indeks Surabaya: 1

// Urutkan
kota.Sort();
Console.WriteLine(string.Join(", ", kota));
// Output: Bandung, Jakarta, Makassar, Medan, Surabaya

Collection Initializer dan var

// Cara modern — lebih ringkas
var mahasiswa = new List<string> { "Ali", "Budi", "Candra" };

// Target-typed new expression (C# 9+)
List<int> angka = new() { 1, 2, 3, 4, 5 };

Dictionary<TKey, TValue> — Pasangan Key-Value

var populasi = new Dictionary<string, long>
{
    { "Jakarta", 10_560_000 },
    { "Surabaya", 2_874_000 },
    { "Bandung", 2_444_000 }
};

// Akses nilai
Console.WriteLine(populasi["Jakarta"]);
// Output: 10560000

// Tambah atau update elemen
populasi["Medan"] = 2_435_000;
populasi["Jakarta"] = 10_600_000; // Update existing

// Pengecekan yang aman
if (populasi.TryGetValue("Bali", out long pop_bali))
{
    Console.WriteLine($"Populasi Bali: {pop_bali}");
}
else
{
    Console.WriteLine("Data Bali tidak ditemukan");
}
// Output: Data Bali tidak ditemukan

// Iterasi
foreach (var (kota, pop) in populasi)
{
    Console.WriteLine($"{kota}: {pop:N0} jiwa");
}

Gunakan TryGetValue() daripada dict[key] langsung — akses langsung melempar KeyNotFoundException jika key tidak ada.

Queue dan Stack

// Queue: FIFO (First In, First Out) — seperti antrian kasir
var antrian = new Queue<string>();
antrian.Enqueue("Pelanggan A");
antrian.Enqueue("Pelanggan B");
antrian.Enqueue("Pelanggan C");

Console.WriteLine($"Sedang dilayani: {antrian.Dequeue()}");
// Output: Sedang dilayani: Pelanggan A
Console.WriteLine($"Berikutnya: {antrian.Peek()}");
// Output: Berikutnya: Pelanggan B (tidak dihapus)

// Stack: LIFO (Last In, First Out) — seperti tumpukan piring
var riwayat = new Stack<string>();
riwayat.Push("Buka halaman A");
riwayat.Push("Buka halaman B");
riwayat.Push("Buka halaman C");

Console.WriteLine($"Undo: {riwayat.Pop()}");
// Output: Undo: Buka halaman C
Console.WriteLine($"Halaman saat ini: {riwayat.Peek()}");
// Output: Halaman saat ini: Buka halaman B

LINQ — Language Integrated Query

LINQ adalah fitur revolusioner C# yang memungkinkan query data secara deklaratif — seperti SQL tapi untuk koleksi C#.

LINQ Method Syntax

var produk = new List<(string nama, int harga, string kategori)>
{
    ("Laptop", 15_000_000, "Elektronik"),
    ("Mouse",    250_000, "Elektronik"),
    ("Baju",     150_000, "Fashion"),
    ("Sepatu",   500_000, "Fashion"),
    ("Monitor",  3_500_000, "Elektronik"),
    ("Tas",      350_000, "Fashion"),
};

// Filter: hanya elektronik
var elektronik = produk.Where(p => p.kategori == "Elektronik");

// Transform: ambil nama saja
var nama_produk = produk.Select(p => p.nama);

// Sort
var termahal = produk.OrderByDescending(p => p.harga);

// Gabungan: elektronik di bawah 1 juta, urutkan
var elektronik_murah = produk
    .Where(p => p.kategori == "Elektronik" && p.harga < 1_000_000)
    .OrderBy(p => p.harga)
    .Select(p => $"{p.nama}: Rp {p.harga:N0}");

foreach (var item in elektronik_murah)
    Console.WriteLine(item);
// Output: Mouse: Rp 250.000

LINQ Aggregasi

var nilai = new List<int> { 85, 92, 78, 95, 88, 72, 91 };

Console.WriteLine($"Rata-rata : {nilai.Average():F1}");    // Output: 85.9
Console.WriteLine($"Nilai max : {nilai.Max()}");            // Output: 95
Console.WriteLine($"Nilai min : {nilai.Min()}");            // Output: 72
Console.WriteLine($"Total     : {nilai.Sum()}");            // Output: 601
Console.WriteLine($"Lulus (≥80): {nilai.Count(n => n >= 80)}"); // Output: 5

// FirstOrDefault: kembalikan null jika tidak ada (tidak throw exception)
int nilai_pertama_a = nilai.FirstOrDefault(n => n >= 90);
Console.WriteLine(nilai_pertama_a); // Output: 92

LINQ Query Syntax (SQL-like)

var mahasiswa = new List<(string nama, double ipk)>
{
    ("Ali", 3.75), ("Budi", 3.20), ("Candra", 3.90),
    ("Dewi", 3.50), ("Eko", 2.80)
};

// Query syntax — mirip SQL
var cum_laude = from m in mahasiswa
                where m.ipk >= 3.5
                orderby m.ipk descending
                select new { m.nama, m.ipk };

foreach (var m in cum_laude)
    Console.WriteLine($"{m.nama}: {m.ipk}");
// Output:
// Candra: 3.9
// Ali: 3.75
// Dewi: 3.5

Pertanyaan yang Sering Diajukan

Kapan menggunakan List<T> vs array?

Gunakan List<T> sebagai default untuk koleksi yang ukurannya bisa berubah (add/remove). Gunakan array hanya jika ukuran tetap dan performa sangat kritis, atau saat berinteraksi dengan API yang membutuhkan array. Dalam praktik sehari-hari, List<T> adalah pilihan yang lebih aman dan fleksibel.

Apa itu LINQ dan apakah selalu lebih baik dari loop biasa?

LINQ adalah cara deklaratif untuk bekerja dengan koleksi — kamu menyatakan apa yang kamu inginkan, bukan bagaimana cara mendapatkannya. LINQ lebih mudah dibaca untuk operasi filter/transform sederhana. Tapi untuk operasi kompleks dengan banyak kondisi atau yang butuh optimasi performa, loop biasa bisa lebih mudah dipahami. Gunakan LINQ untuk keterbacaan, loop untuk kontrol penuh.

Mengapa ada TryGetValue untuk Dictionary, bukan akses langsung?

Akses dict["key"] melempar KeyNotFoundException jika key tidak ada — ini adalah exception yang harus ditangani. TryGetValue mengembalikan false dan nilai default jika key tidak ada, tanpa exception. Ini lebih aman dan lebih performant karena tidak ada overhead exception handling. Gunakan TryGetValue saat kamu tidak yakin apakah key ada.

Apa perbedaan First() dan FirstOrDefault()?

First() melempar InvalidOperationException jika koleksi kosong atau tidak ada elemen yang memenuhi kondisi. FirstOrDefault() mengembalikan nilai default tipe (null untuk reference type, 0 untuk int, dll.). Gunakan First() saat kamu yakin elemen pasti ada; FirstOrDefault() saat elemen mungkin tidak ada.

Kesimpulan

KoleksiKapan Digunakan
List<T>Koleksi dinamis umum (paling sering dipakai)
Dictionary<K,V>Pencarian cepat berdasarkan key
Queue<T>Antrian (FIFO): pemrosesan berurutan
Stack<T>Tumpukan (LIFO): undo/history
LINQ .Where()Filter data
LINQ .Select()Transformasi data
LINQ .OrderBy()Pengurutan

Artikel sebelumnya: Fungsi dan Method di C# — cara membuat method di C#.

Langkah selanjutnya: Class dan Object di C# — dasar pemrograman berorientasi objek di C#.

Artikel Terkait