Ders 12 / 17
Map ve Set
Nesneyi sözlük olarak kullanmanın sınırları, anahtar kimliğini koruyan eşleme türü, tekil değer kümeleri ve iki kuruluşun gruplama üzerinde karşılaştırılması.
İçindekiler
Kursun ilk dersinde prototipsiz nesne, sonraki derslerde de aynı önlem yeniden karşımıza çıktı: kalibrasyon tablosunda, not alma önbelleğinde ve gruplama birikecinde. Her seferinde neden aynıydı — anahtarları program dışından gelen bir eşlemede, nesnenin zincirinden gelen adlar sonucu bozuyordu.
Bu, nesneyi sözlük olarak kullanmanın tek sınırı değil. Anahtarlar dizgiye çevrilir, sıra
kuralı beklenenden farklıdır ve eleman sayısı doğrudan okunamaz. Dil bu iş için iki tür
sunar: anahtar–değer çiftleri için Map, tekil değerler için Set. Ders önce sınırları
gösterir, sonra iki türü tanıtır.
Nesnenin Sözlük Olarak Sınırları
Nesne özelliklerinin anahtarı yalnızca dizgi ya da simge olabilir. Başka türden bir anahtar verildiğinde dizgiye çevrilir.
const sozluk = {}; const anahtarNesnesi = { sensor: "S-01" }; const digerNesne = { sensor: "S-02" }; sozluk[1] = "sayi bir"; sozluk["1"] = "dizgi bir"; sozluk[true] = "mantiksal"; sozluk[anahtarNesnesi] = "birinci nesne"; sozluk[digerNesne] = "ikinci nesne"; console.log(Object.keys(sozluk).join(" | ")); console.log(sozluk[1]); console.log(sozluk[anahtarNesnesi]); console.log(Object.keys(sozluk).length); const sirali = {}; sirali["S-02"] = 1; sirali[10] = 2; sirali["S-01"] = 3; sirali[2] = 4; console.log(Object.keys(sirali).join(",")); const kirli = { sensor: "S-01" }; console.log("toString" in kirli); console.log(Object.hasOwn(kirli, "toString")); console.log(typeof kirli["toString"]);
1 | true | [object Object] dizgi bir ikinci nesne 3 2,10,S-02,S-01 true false function
Üç sınır görünür durumda. Birincisi, 1 ile "1" aynı anahtardır; ikinci atama birinciyi
ezmiştir. İkincisi daha ağırdır: iki farklı nesne aynı "[object Object]" dizgisine
çevrildiği için tek bir anahtar hâline gelir — nesneler anahtar olarak kullanılamaz.
Üçüncüsü sıradır: tam sayıya benzeyen anahtarlar artan sayısal düzende öne alınır, diğerleri
ekleme sırasını korur.
Son üç satır tanıdık sorunu yineler. Sözlükte toString diye bir anahtar yoktur ama sorgu
onu bulur; anahtarların dışarıdan geldiği her durumda Object.hasOwn ya da prototipsiz
nesne kullanılmalıdır.
Anahtar Kimliğini Koruyan Eşleme
Map, anahtarları dönüştürmez. Her tür değer anahtar olabilir ve karşılaştırma kimlik
üzerinden yapılır.
const anahtarNesnesi = { sensor: "S-01" }; const digerNesne = { sensor: "S-02" }; const defter = new Map(); defter.set(1, "sayi bir"); defter.set("1", "dizgi bir"); defter.set(anahtarNesnesi, "birinci nesne"); defter.set(digerNesne, "ikinci nesne"); defter.set(NaN, "tanimsiz olcum"); console.log(defter.size); console.log(defter.get(1)); console.log(defter.get("1")); console.log(defter.get(anahtarNesnesi)); console.log(defter.get({ sensor: "S-01" })); console.log(defter.get(NaN)); console.log(defter.has(digerNesne)); defter.delete(digerNesne); console.log(defter.size); const anahtarTurleri = [...defter.keys()].map((a) => typeof a).join(","); console.log(anahtarTurleri); const sirali = new Map(); sirali.set("S-02", 1); sirali.set(10, 2); sirali.set("S-01", 3); sirali.set(2, 4); console.log([...sirali.keys()].join(","));
5 sayi bir dizgi bir birinci nesne undefined tanimsiz olcum true 4 number,string,object,number S-02,10,S-01,2
1 ile "1" ayrı anahtarlardır. Nesne anahtarı kimliğiyle saklanır: aynı içerikli
başka bir nesneyle sorgulandığında sonuç bulunamaz. Programlama Temelleri kursundaki
Değişkenler ve Bağlama dersindeki kimlik–eşitlik ayrımı burada doğrudan işler.
NaN anahtarının bulunabilmesi bir ayrıntıya işaret eder: karşılaştırma katı eşitlikle
değil, NaN değerini kendisine eşit sayan bir kuralla yapılır. Aynı kural Set için de
geçerlidir.
Son satır sıra kuralını gösterir: Map yalnızca ekleme sırasını korur, sayısal anahtarları
öne almaz. size özelliği eleman sayısını doğrudan verir; nesnede aynı bilgi için tüm
anahtarların listelenmesi gerekir.
Karma tablosu ile ilişkisi de burada kurulur. Veri Yapıları kursundaki Karma Tabloları
dersinde incelenen ortalama sabit maliyetli erişim, hem nesne özelliklerinin hem de
Map yapısının altında yatan davranıştır; Map bunun anahtar kimliğini koruyan biçimidir.
Dönüşümler ve Gezinme
Map ile nesne arasında iki yönlü dönüşüm yerleşiktir. Dizileştirmede ise fark önemlidir.
const kayitNesnesi = { "S-01": 21.4, "S-02": 19.8, "S-03": 18.2 }; const nesnedenMap = new Map(Object.entries(kayitNesnesi)); console.log(nesnedenMap.size); console.log(nesnedenMap.get("S-02")); const geriNesne = Object.fromEntries(nesnedenMap); console.log(JSON.stringify(geriNesne)); console.log(JSON.stringify(nesnedenMap)); console.log(JSON.stringify([...nesnedenMap])); const ciftlerden = new Map([ ["S-01", 21.4], ["S-02", 19.8], ]); console.log([...ciftlerden.entries()].map(([a, d]) => `${a}=${d}`).join(" ")); let toplam = 0; for (const [, deger] of nesnedenMap) toplam += deger; console.log(toplam.toFixed(1)); nesnedenMap.forEach((deger, anahtar) => { if (anahtar === "S-01") console.log(`forEach: ${anahtar} -> ${deger}`); });
3
19.8
{"S-01":21.4,"S-02":19.8,"S-03":18.2}
{}
[["S-01",21.4],["S-02",19.8],["S-03",18.2]]
S-01=21.4 S-02=19.8
59.4
forEach: S-01 -> 21.4
Dördüncü satır kritiktir: JSON.stringify bir Map nesnesini boş nesne olarak
dizileştirir. Neden ilk derste kurulmuştu — dizileştirme kendi sayılabilir
özelliklerle çalışır, Map içeriği ise özellik olarak tutulmaz. Verinin taşınması
gerekiyorsa çiftler dizisine çevrilmelidir. Aynı sorunun genel çözümü kursun son dersinde
ele alınacak.
for...of döngüsü her adımda bir çift verir; ayrıştırmayla anahtar ve değer ayrılabilir.
forEach yönteminde argüman sırası ters olduğu için — önce değer, sonra anahtar —
karıştırılmaya açıktır.
Tekil Değerler
Set, aynı değeri birden çok kez tutmayan bir koleksiyondur. Veri Yapıları kursundaki
Kümeler ve Çok Kümeler dersinde tanıtılan kümenin dildeki karşılığıdır.
const okunanSensorler = ["S-01", "S-02", "S-01", "S-03", "S-02", "S-01"]; const tekiller = new Set(okunanSensorler); console.log(tekiller.size); console.log([...tekiller].join(",")); console.log(tekiller.has("S-02")); console.log(tekiller.has("S-99")); const sayiKumesi = new Set([1, 1, NaN, NaN, 0, -0]); console.log(sayiKumesi.size); console.log([...sayiKumesi].join(",")); const nesneKumesi = new Set([{ sensor: "S-01" }, { sensor: "S-01" }]); console.log(nesneKumesi.size); const bakimdakiler = new Set(["S-02", "S-04"]); const kesisim = [...tekiller].filter((s) => bakimdakiler.has(s)); const fark = [...tekiller].filter((s) => !bakimdakiler.has(s)); const birlesim = [...new Set([...tekiller, ...bakimdakiler])]; console.log(kesisim.join(",")); console.log(fark.join(",")); console.log(birlesim.join(","));
3 S-01,S-02,S-03 true false 3 1,NaN,0 2 S-02 S-01,S-03 S-01,S-02,S-03,S-04
Tekilleştirme tek satıra iner ve ekleme sırası korunur. Sayısal örnek karşılaştırma
kuralını netleştirir: iki NaN değeri aynı sayılır — katı eşitlikte olmayan bir davranış —
buna karşılık 0 ile -0 da aynı sayılır. Nesneler yine kimlikleriyle karşılaştırılır;
aynı içerikli iki nesne ayrı elemanlardır.
Küme işlemleri, has sorgusunun ortalama sabit maliyetli olmasından yararlanır. Aynı
işlemi dizilerle yapmak, her eleman için doğrusal arama gerektirir ve maliyeti iki
kümenin boyutlarının çarpımına çıkarır.
Gruplamada Karşılaştırma
Yüksek Mertebeden Fonksiyonlar dersindeki gruplama örneği, iki kuruluşu yan yana koymak
için uygun bir sınamadır. Sensör adları veri kaynağından geldiğine göre, aralarında
constructor gibi bir ad da bulunabilir.
const kayitlar = [ { sensor: "S-01", deger: 21.4 }, { sensor: "S-02", deger: 19.8 }, { sensor: "S-01", deger: 25.1 }, { sensor: "constructor", deger: 0.5 }, ]; function naifGrupla(liste) { const grup = {}; for (const kayit of liste) { if (!grup[kayit.sensor]) grup[kayit.sensor] = []; grup[kayit.sensor].push(kayit.deger); } return grup; } function nesneyleGrupla(liste) { const grup = {}; for (const kayit of liste) { if (!Array.isArray(grup[kayit.sensor])) grup[kayit.sensor] = []; grup[kayit.sensor].push(kayit.deger); } return grup; } function mapIleGrupla(liste) { const grup = new Map(); for (const kayit of liste) { if (!grup.has(kayit.sensor)) grup.set(kayit.sensor, []); grup.get(kayit.sensor).push(kayit.deger); } return grup; } try { naifGrupla(kayitlar); } catch (hata) { console.log(`naif surum: ${hata.constructor.name}`); } const nesneGrubu = nesneyleGrupla(kayitlar); const mapGrubu = mapIleGrupla(kayitlar); console.log(Object.keys(nesneGrubu).join(",")); console.log([...mapGrubu.keys()].join(",")); console.log(nesneGrubu["S-01"].join(",")); console.log(mapGrubu.get("S-01").join(",")); console.log(nesneGrubu["constructor"].join(",")); console.log(mapGrubu.get("constructor").join(",")); console.log(Object.keys(nesneGrubu).length === mapGrubu.size);
naif surum: TypeError S-01,S-02,constructor S-01,S-02,constructor 21.4,25.1 21.4,25.1 0.5 0.5 true
Naif sürüm hata verir: grup["constructor"] ifadesi zincirden gelen fonksiyonu bulur, bu
değer doğru sayıldığı için dizi hiç yaratılmaz ve fonksiyona push çağrılır. Düzeltilmiş
sürüm doğrulamayı tür denetimiyle yaptığı için çalışır — ama düzeltmenin gerekli olduğunu
bilmek gerekir.
Map ile yazılan sürümde böyle bir tuzak yoktur; has sorgusu zincire bakmaz, çünkü
Map içeriği özellik olarak tutulmaz. Kural olarak: anahtarlar sabit ve programcı
tarafından yazılmışsa nesne, veri kaynağından geliyorsa Map kullanılır.
Özet
- Nesne anahtarları dizgiye çevrilir; farklı nesneler aynı anahtara düşer ve tam sayıya benzeyen anahtarlar sıralamada öne alınır.
Mapanahtarları dönüştürmez, kimlikleriyle saklar, ekleme sırasını korur vesizeile eleman sayısını doğrudan verir.NaNdeğeri hemMaphemSetiçinde kendisine eşit sayılır; nesneler kimlikleriyle karşılaştırılır.JSON.stringifybirMapnesnesini boş nesne olarak dizileştirir; içerik çiftler dizisine çevrilmelidir.Settekilleştirmeyi tek adıma indirir; küme işlemleri sabit maliyetli sorgudan yararlanır.- Anahtarlar veri kaynağından geliyorsa
Map, sabit ve programda yazılıysa nesne kullanılır.
Sonraki Adım
Map bir anahtarı sakladığı sürece, o anahtar nesnesi bellekte kalır. Bir nesneye ek
bilgi iliştirmek için kurulan tablolar bu yüzden nesnelerin ömrünü uzatır: tablodan
silinmeyen her giriş, artık kullanılmayan bir nesneyi yaşatır. Sonraki ders, tuttukları
nesnelerin toplanmasını engellemeyen zayıf koleksiyonları ve bunların özel veri saklamada
oynadığı rolü ele alacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.