Ahmet Balaman LogoAhmet Balaman

Dart Collections: List, HashSet ve HashMap ile Veri Yönetimi

personAhmet Balaman
calendar_today
DartCollectionsListHashSetHashMapVeri Yapıları

Collections - Veri Yapılarıyla Tanışmam

Bugün Dart'ın veri yapılarına (Collections) daldım. List, HashSet ve HashMap. İlk başta "bunların hepsi aynı şey değil mi" diye düşündüm ama her birinin kendine özgü kullanım alanları varmış.

Canlı Demo: Dart Collections Örnekleri

List, HashSet ve HashMap kullanımlarını interaktif olarak deneyin:
|

List - Klasik Diziler

List'ler en çok bildiğimiz veri yapısı. Diğer dillerdeki array'lere benziyor. Her elemanın bir index'i var (0'dan başlıyor) ve sıralı çalışıyor.

İlk List Denemelerim

void main() {
  List<int> sayilar = [3, 4, 5];
  List<String> isimler = ["Ahmet", "Mehmet", "Selda"];
  List<double> oranlar = [3.2, 3.3, 3.5];
  
  print(sayilar);    // [3, 4, 5]
  print(isimler);    // [Ahmet, Mehmet, Selda]
  print(oranlar);    // [3.2, 3.3, 3.5]
}

Veri Ekleme ve Silme

// Ekleme
sayilar.add(32);
isimler.add("Yeni isim");
oranlar.add(3.4);

// Belirli bir yere ekleme
sayilar.insert(0, 100); // Başa ekler

// Güncelleme
sayilar[0] = 50; // İlk elemanı değiştir

// Silme
sayilar.removeAt(0);     // 0. index'i sil
isimler.remove("Ahmet"); // "Ahmet"i sil
oranlar.clear();         // Hepsini sil

List'in Kullanışlı Özellikleri

Bu özellikleri öğrendikçe işim çok kolaylaştı:

List<int> sayilar = [10, 20, 30, 40];

print(sayilar.isEmpty);      // false
print(sayilar.isNotEmpty);   // true
print(sayilar.length);       // 4
print(sayilar.first);        // 10
print(sayilar.last);         // 40
print(sayilar.contains(20)); // true

For Döngüsü ile Okuma

Liste elemanlarını okumak için foreach kullanıyorum:

List<double> oranlar = [3.2, 3.3, 3.5];

for (var oran in oranlar) {
  print("Oran: $oran");
}

Sınıftan Nesne Listesi

Şimdi daha gerçekçi bir örnek yapalım. Öğrenci listesi:

class Ogrenci {
  int? no;
  String? ad;
  String? sinif;
  
  Ogrenci(this.no, this.ad, this.sinif);
}

void main() {
  var ogrenci1 = Ogrenci(33, "Ahmet", "3. Sınıf");
  var ogrenci2 = Ogrenci(22, "Mehmet", "2. Sınıf");
  var ogrenci3 = Ogrenci(199, "Ayşe", "4. Sınıf");
  
  // Öğrenci listesi oluştur
  List<Ogrenci> ogrenciler = [];
  ogrenciler.add(ogrenci1);
  ogrenciler.add(ogrenci2);
  ogrenciler.add(ogrenci3);
  
  // Listeyi dolaş
  for (var ogrenci in ogrenciler) {
    print("${ogrenci.no} numaralı ${ogrenci.ad}");
    print("Sınıfı: ${ogrenci.sinif}");
    print("***************");
  }
}

Listeyi Sıralama

Öğrencileri numaraya göre sıralamak istedim:

// Küçükten büyüğe sıralama
Comparator<Ogrenci> siralama = (x, y) => x.no!.compareTo(y.no!);
ogrenciler.sort(siralama);

// Artık öğrenciler numaraya göre sıralı
for (var ogrenci in ogrenciler) {
  print("${ogrenci.no} - ${ogrenci.ad}");
}

Filtreleme (Iterable)

100'den küçük numarası olan öğrencileri bulmak:

Iterable<Ogrenci> filtrelenmisList = ogrenciler.where((ogrenci) {
  return ogrenci.no! < 100;
});

List<Ogrenci> yeniListe = filtrelenmisList.toList();

for (var ogrenci in yeniListe) {
  print("${ogrenci.no} - ${ogrenci.ad}");
}

Bu where metodu çok işime yarıyor. Mesela Flutter'da bir arama özelliği yapıyorsanız, kullanıcının girdiği metne göre listeyi filtreleyebilirsiniz.

HashSet - Rastgele ve Tekil

HashSet'leri öğrendiğimde "List'ten ne farkı var" diye düşündüm. Sonra iki önemli fark olduğunu gördüm:

  1. Index yok: Elemanlar rastgele sırada
  2. Aynı eleman iki kere eklenemez: Her eleman tekil olmalı
import 'dart:collection';

void main() {
  HashSet<int> sayilar = HashSet<int>();
  sayilar.add(5);
  sayilar.add(3);
  sayilar.add(8);
  sayilar.add(3); // Bu eklenmeyecek çünkü zaten var
  
  print(sayilar); // {5, 3, 8} veya başka bir sırada
  
  // Başka bir yöntem
  HashSet<int> isimler = HashSet.from([1, 2, 3, 4, 1]);
  print(isimler); // {1, 2, 3, 4} - Tekrar eden 1 eklenmedi
}

Ne Zaman HashSet Kullanmalı?

  • Sıralama önemli değilse
  • Tekrar eden elemanları istemiyorsanız
  • Hızlı arama yapmanız gerekiyorsa (List'ten daha hızlı)

Nesne ile HashSet

class Ogrenci {
  int? no;
  String? ad;
  String? sinif;
  
  Ogrenci(this.no, this.ad, this.sinif);
  
  // Aynı numaralı öğrenciler aynı sayılsın
  @override
  int get hashCode => this.no!;
  
  @override
  bool operator ==(Object other) {
    if (no == (other as Ogrenci).no) {
      return true;
    } else {
      return false;
    }
  }
}

void main() {
  var o1 = Ogrenci(123, "Ahmet", "11A");
  var o2 = Ogrenci(124, "Mehmet", "11A");
  var o3 = Ogrenci(123, "Farklı İsim", "12B"); // Aynı numara!
  
  HashSet<Ogrenci> ogrenciler = HashSet<Ogrenci>();
  ogrenciler.add(o1);
  ogrenciler.add(o2);
  ogrenciler.add(o3); // Bu eklenmeyecek çünkü no'su o1 ile aynı
  
  print("Toplam öğrenci: ${ogrenciler.length}"); // 2
}

hashCode ve operator == kısımları başta karmaşık geldi ama şunu yapıyor: "Hangi özelliğe göre aynı olduklarına karar verilsin?" Burada numara aynıysa aynı öğrenci sayıyoruz.

HashMap - Anahtar-Değer İkilisi

HashMap benim en çok zorlandığım yapıydı. Ama anladıktan sonra en çok sevdiğim oldu. Her değer bir anahtara (key) bağlı.

import 'dart:collection';

void main() {
  HashMap<int, String> telefonRehberi = HashMap<int, String>();
  
  telefonRehberi[123] = "Ahmet";
  telefonRehberi[456] = "Mehmet";
  telefonRehberi[789] = "Ayşe";
  
  print(telefonRehberi[123]); // Ahmet
}

Şöyle düşünün: Bir apartman var. Her dairenin numarası (key) var ve her dairede bir kişi (value) yaşıyor.

TC Kimlik ile Vatandaş Örneği

class TcVatandasi {
  int? tc;
  String? isim;
  String? soyisim;
  
  TcVatandasi(this.tc, this.isim, this.soyisim);
}

void main() {
  var kisi1 = TcVatandasi(12345678901, "Ahmet", "Balaman");
  var kisi2 = TcVatandasi(98765432109, "Mehmet", "Yılmaz");
  var kisi3 = TcVatandasi(55555555555, "Ayşe", "Demir");
  
  // TC numarası key, kişi value
  HashMap<int, TcVatandasi> vatandaslar = HashMap<int, TcVatandasi>();
  
  vatandaslar[kisi1.tc!] = kisi1;
  vatandaslar[kisi2.tc!] = kisi2;
  vatandaslar[kisi3.tc!] = kisi3;
  
  // TC ile kişi bulma
  var bulunanKisi = vatandaslar[12345678901];
  print("${bulunanKisi?.isim} ${bulunanKisi?.soyisim}");
}

HashMap'i Dolaşmak

var keyler = vatandaslar.keys;

for (var tc in keyler) {
  var kisi = vatandaslar[tc];
  if (kisi != null) {
    print("TC: ${kisi.tc}");
    print("İsim: ${kisi.isim} ${kisi.soyisim}");
    print("**********");
  }
}

List vs HashSet vs HashMap

Hangisini ne zaman kullanmalı? Kendi çıkardığım sonuçlar:

Özellik List HashSet HashMap
Sıralı mı? ✅ Evet ❌ Hayır ❌ Hayır
Tekrar eden değer ✅ Olabilir ❌ Olamaz ✅ Value olabilir
Index ile erişim ✅ Evet ❌ Hayır ❌ Hayır
Key ile erişim ❌ Hayır ❌ Hayır ✅ Evet
Hız Orta Hızlı Hızlı

Kullanım Örnekleri

  • List: Alışveriş sepeti, yapılacaklar listesi, mesaj listesi
  • HashSet: Etiketler (tags), kategoriler, unique ID'ler
  • HashMap: Ayarlar (key: ayar adı, value: ayar değeri), çeviriler (key: dil kodu, value: çeviri)

Flutter'da Kullanım

Flutter'da en çok List kullanıyorum. Mesela bir ListView yapıyorsanız:

List<String> urunler = ["Elma", "Armut", "Muz"];

ListView.builder(
  itemCount: urunler.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(urunler[index]),
    );
  },
)

HashMap'i genelde dil çevirileri için kullanıyorum:

HashMap<String, String> ceviriler = HashMap();
ceviriler["hello"] = "Merhaba";
ceviriler["goodbye"] = "Hoşça kal";

print(ceviriler["hello"]); // Merhaba

Bugün Ne Öğrendim?

  • List sıralı ve tekrar eden değerlere izin veriyor
  • HashSet hızlı ve tekil elemanlar için
  • HashMap anahtar-değer çiftleri için mükemmel
  • Filtreleme için where metodu çok işe yarıyor
  • hashCode ve operator == ile özel karşılaştırma yapabiliyoruz

Yarın Try-Catch ve hata yönetimi konusuna bakacağım. Flutter'da hata yönetimi çok önemliymiş.


İletişim:

Kodlu günler!