flowchart TD
A["students: list"] --> B["record 1: dict"]
A --> C["record 2: dict"]
A --> D["record 3: dict"]
B --> B1["number"]
B --> B2["name"]
B --> B3["grade"]
Kayıtlar ve iç içe veri yapıları
Programlama Temelleri dersinde liste içinde sözlük gibi iç içe yapılarla tanıştınız. Bu hafta aynı sözdizimini yeniden öğrenmeyeceğiz. Asıl sorumuz şudur:
Aynı kayıt kümesini farklı biçimlerde düzenlersek hangi işlemler kolaylaşır, hangileri zorlaşır?
Bu derste henüz sınıf tasarımı yapmıyoruz. Bu nedenle kayıtları çoğunlukla sözlüklerle temsil edeceğiz; ancak kayıtların hangi dış yapı içinde tutulduğu problem gereksinimine göre değişecektir.
1 Bu hafta neleri yapabilmelisiniz?
Bölümün sonunda:
- bir kaydı sözlükle temsil edebilmeli,
- çok sayıda kaydı liste içinde sözlüklerle düzenleyebilmeli,
- aynı kayıtları kimliğe göre indeksleyen bir
dictgörünümü oluşturabilmeli, - gruplama için
dict+listyapısını kullanabilmeli, - kayıt ekleme, güncelleme, filtreleme ve özetleme işlemleri gerçekleştirebilmeli,
- aynı verinin farklı temsil biçimlerinin hangi işlemleri kolaylaştırdığını açıklayabilmeli,
- sığ kopya ve ortak referans davranışını iç içe yapılarda fark edebilmelisiniz.
2 Bir kayıt: alan adları neden önemlidir?
Bir öğrenciyi tek tek değişkenlerle tutabiliriz:
number = 102
name = "Bora"
department = "Yazılım"
grade = 78Fakat bu değerlerin aynı öğrenciye ait olduğu yapısal olarak görünmez. Sözlük bu ilişkiyi daha açık hâle getirir:
#| edit: false
#| completion: false
student = {
"number": 102,
"name": "Bora",
"department": "Yazılım",
"grade": 78,
}
print(student["name"])
print(student["grade"])
Burada sözlük, alan adlarını doğrudan görünür kılar.
3 Temsil 1 — liste içinde kayıtlar
Bir sınıftaki öğrencileri liste içinde sözlüklerle tutabiliriz:
#| edit: false
#| completion: false
students = [
{"number": 101, "name": "Ayşe", "department": "Yazılım", "grade": 86},
{"number": 102, "name": "Bora", "department": "Siber", "grade": 72},
{"number": 103, "name": "Cem", "department": "Yazılım", "grade": 91},
]
for student in students:
print(student["number"], student["name"])
Bu temsil özellikle şu işlemler için doğaldır:
- kayıtların sırasını koruma,
- bütün kayıtları dolaşma,
- filtreleme,
- sıralı rapor üretme.
4 Liste üzerinde kimliğe göre arama
Öğrenci numarasına göre kayıt bulmak için listeyi dolaşabiliriz:
#| edit: false
#| completion: false
def find_by_number(students, number):
for student in students:
if student["number"] == number:
return student
return None
students = [
{"number": 101, "name": "Ayşe", "grade": 86},
{"number": 102, "name": "Bora", "grade": 72},
{"number": 103, "name": "Cem", "grade": 91},
]
print(find_by_number(students, 102))
Bu çözüm yanlış değildir. Fakat aynı tür arama binlerce kez yapılacaksa her seferinde listeyi dolaşmak daha az uygun olabilir.
5 Temsil 2 — kimliğe göre indekslenmiş sözlük
Aynı kayıtları numaradan kayda erişecek biçimde düzenleyebiliriz:
#| edit: false
#| completion: false
students_by_number = {
101: {"name": "Ayşe", "department": "Yazılım", "grade": 86},
102: {"name": "Bora", "department": "Siber", "grade": 72},
103: {"name": "Cem", "department": "Yazılım", "grade": 91},
}
print(students_by_number[102])
Bu temsil, “102 numaralı öğrenci kim?” sorusunu doğrudan ifade eder.
5.1 Aynı veri, farklı güçlü taraf
| Temsil | Güçlü olduğu işlem |
|---|---|
list[dict] |
sırayla dolaşma, filtreleme, raporlama |
dict[id -> record] |
kimliğe göre sık erişim |
Bir temsilin daha iyi olması problemden bağımsız değildir. En sık yapılan işlem, dış veri yapısının seçimini etkiler.
6 Temsil 3 — gruplama: dict + list
Bazen anahtardan tek bir kayda değil, bir kayıt grubuna ulaşmak isteriz. Örneğin öğrencileri bölüme göre gruplayalım:
#| edit: false
#| completion: false
students = [
{"name": "Ayşe", "department": "Yazılım"},
{"name": "Bora", "department": "Siber"},
{"name": "Cem", "department": "Yazılım"},
{"name": "Deniz", "department": "Siber"},
]
groups = {}
for student in students:
department = student["department"]
if department not in groups:
groups[department] = []
groups[department].append(student)
for department, members in groups.items():
print(department, "->", [member["name"] for member in members])
Burada dış sözlüğün her anahtarı bir grubu, değer olarak tutulan liste ise o grubun üyelerini temsil eder.
7 Üç temsili birlikte görelim
flowchart LR
R["Aynı kayıt kümesi"] --> L["list[dict]"]
R --> I["dict[id → record]"]
R --> G["dict[group → list[record]]"]
L --> L1["sıra / filtre / rapor"]
I --> I1["kimliğe göre erişim"]
G --> G1["gruba göre erişim"]
Gerçek programlarda bu görünümlerden birden fazlası aynı anda bulunabilir.
8 Aynı kayıtların birden çok yapıdan görülmesi
Bir listedeki kayıtları indeksleyen sözlüğü sonradan oluşturabiliriz:
#| edit: false
#| completion: false
students = [
{"number": 101, "name": "Ayşe", "grade": 86},
{"number": 102, "name": "Bora", "grade": 72},
]
by_number = {}
for student in students:
by_number[student["number"]] = student
by_number[102]["grade"] = 80
print(students)
print(by_number[102])
Neden listedeki kayıt da değişti? Çünkü students listesi ile by_number sözlüğü aynı öğrenci sözlüğü nesnesine referans veriyor.
Bu davranış yararlı olabilir: tek kaydı iki ayrı yerde kopyalamadan iki farklı erişim biçimi oluştururuz. Ancak bağımsız kopya bekliyorsak hata kaynağı olabilir.
9 Filtreleme kalıbı
Belirli koşula uyan kayıtları yeni bir listede toplayalım:
#| edit: false
#| completion: false
students = [
{"name": "Ayşe", "department": "Yazılım", "grade": 86},
{"name": "Bora", "department": "Siber", "grade": 72},
{"name": "Cem", "department": "Yazılım", "grade": 91},
{"name": "Deniz", "department": "Siber", "grade": 64},
]
selected = []
for student in students:
if student["department"] == "Yazılım" and student["grade"] >= 80:
selected.append(student)
for student in selected:
print(student["name"], student["grade"])
Filtrelemede bütün kayıtları görmek gerektiği için list[dict] temsili doğal bir seçimdir.
10 Alıştırma — düşük stoklu ürünler
stock değeri 10’dan küçük ürünlerin adlarını low_stock listesine ekleyin.
#| exercise: hafta04-filtre
#| completion: false
#| persist: true
products = [
{"code": "K1", "name": "Kalem", "stock": 18},
{"code": "D2", "name": "Defter", "stock": 6},
{"code": "S3", "name": "Silgi", "stock": 9},
{"code": "C4", "name": "Cetvel", "stock": 15},
]
low_stock = []
for product in products:
# Burayı tamamlayın.
pass
print(low_stock)
Beklenen sonuç:
['Defter', 'Silgi']
#| exercise: hafta04-filtre
#| check: true
scope = {}
try:
exec(user_code, scope)
correct = scope.get("low_stock") == ["Defter", "Silgi"]
except Exception:
correct = False
feedback = (
{"correct": True, "message": "Düşük stoklu ürünler doğru filtrelendi."}
if correct
else {"correct": False, "message": "Her ürün için stock < 10 koşulunu kontrol edip product['name'] değerini ekleyin."}
)
feedback
if product["stock"] < 10: koşulundan sonra low_stock.append(...) kullanın.
Solution.
for product in products:
if product["stock"] < 10:
low_stock.append(product["name"])11 Alıştırma — kimliğe göre indeks oluştur
Aşağıdaki ürünleri code alanını anahtar olarak kullanarak by_code sözlüğünde indeksleyin.
#| exercise: hafta04-index
#| completion: false
#| persist: true
products = [
{"code": "K1", "name": "Kalem", "stock": 18},
{"code": "D2", "name": "Defter", "stock": 6},
{"code": "S3", "name": "Silgi", "stock": 9},
]
by_code = {}
for product in products:
# Burayı tamamlayın.
pass
print(by_code["D2"])
#| exercise: hafta04-index
#| check: true
scope = {}
try:
exec(user_code, scope)
by_code = scope.get("by_code")
correct = (
isinstance(by_code, dict)
and by_code.get("K1", {}).get("name") == "Kalem"
and by_code.get("D2", {}).get("stock") == 6
and by_code.get("S3", {}).get("name") == "Silgi"
)
except Exception:
correct = False
feedback = (
{"correct": True, "message": "Kayıtlar code alanına göre doğru indekslendi."}
if correct
else {"correct": False, "message": "Her ürün için by_code[product['code']] = product kalıbını kullanın."}
)
feedback
Sözlüğün anahtarı product["code"], değeri ise product kaydının kendisi olabilir.
Solution.
for product in products:
by_code[product["code"]] = product12 Özetleme
Kayıtlardaki sayısal alanları özetlemek için biriktirici kalıbını kullanabiliriz:
#| edit: false
#| completion: false
students = [
{"name": "Ayşe", "grade": 86},
{"name": "Bora", "grade": 72},
{"name": "Cem", "grade": 91},
]
total = 0
for student in students:
total += student["grade"]
average = total / len(students) if students else 0
print("Ortalama:", average)
Bu bölümde önemli olan toplam hesabının kendisinden çok, kayıt yapısındaki belirli alanları sistematik biçimde işleyebilmenizdir.
13 İç içe yapıları okurken adım adım düşünün
Şu ifadeyi inceleyelim:
students[1]["courses"][0]Bunu tek seferde değil adım adım okuyun:
students[1]→ ikinci öğrenci kaydı,["courses"]→ o kaydın ders listesi,[0]→ ilk ders.
Bu alışkanlık, iç içe yapılardaki indeks/anahtar hatalarını azaltır.
14 Sığ kopya tekrar karşımıza çıkıyor
#| edit: false
#| completion: false
record = {"name": "Ayşe", "tags": ["python", "data"]}
copy_record = record.copy()
copy_record["tags"].append("web")
print(record)
print(copy_record)
.copy() dış sözlüğü kopyalar; içteki tags listesi paylaşılmaya devam eder. Bu, 2. haftadaki sığ kopya fikrinin kayıtlar üzerindeki karşılığıdır.
15 Küçük karar çalışması
Aynı öğrenci verisi için aşağıdaki gereksinimlerde hangi temsili önceliklendirirsiniz?
- Bütün öğrencileri kayıt sırasıyla ekranda göstermek.
- Öğrenci numarasına göre saniyede çok sayıda sorgu yapmak.
- Bölüm adına göre o bölümdeki öğrencilerin tamamına ulaşmak.
Seçenekler:
A. list[dict]
B. dict[number -> record]
C. dict[department -> list[record]]
Yanıtınızda yalnızca yapının adını değil, hangi işlemi kolaylaştırdığı bilgisini de yazın.
16 Bölüm özeti
- Bir kayıt sözlükle temsil edilebilir.
- Çok sayıda kayıt için
list[dict]sıralı dolaşma, filtreleme ve raporlama açısından doğaldır. - Aynı kayıtları
dict[id -> record]biçiminde indekslemek kimliğe göre sık erişimi kolaylaştırır. dict[group -> list[record]]gruplama problemlerine uygundur.- Aynı kayıt nesneleri birden çok koleksiyon tarafından referans edilebilir.
- Temsil seçimi sözdizimine değil işlem gereksinimine dayanır.
- İç içe veri yapılarında sığ kopya davranışı önemini korur.
17 Kendinizi kontrol edin
list[dict]hangi işlemlerde doğaldır?- Öğrenci numarasına göre çok sık erişim gerekiyorsa dış temsil nasıl değiştirilebilir?
- Bölüme göre öğrenci gruplamak için hangi yapı kombinasyonu uygundur?
studentslistesi ileby_numbersözlüğü aynı kayıt nesnesini gösteriyorsa birindeki değişiklik neden diğerinde görünür?- Filtreleme için neden çoğu zaman bütün kayıtları dolaşmak gerekir?
- Sığ kopyalanmış bir sözlüğün içindeki liste neden hâlâ paylaşılabilir?