Dart Collections: List, HashSet ve HashMap ile Veri Yönetimi
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 silList'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)); // trueFor 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:
- Index yok: Elemanlar rastgele sırada
- 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"]); // MerhabaBugü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
wheremetodu çok işe yarıyor hashCodeveoperator ==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!