İç içe kayıtlar ve küçük veri işleme

Geçen hafta bir ürünün ad, fiyat, stok bilgilerini bir sözlükte tutmayı gördük. Elimizde birden fazla ürün ya da öğrenci varsa her kaydı bir sözlüğe koyar, bu sözlükleri de bir listede saklarız.

Bu hafta yeni bir Python yapısı öğrenmeyeceğiz. Bildiğimiz liste, sözlük, koşul, döngü ve fonksiyonları birlikte kullanarak küçük veri kümeleriyle çalışacağız. Dört iş yapacağız: koşula uyan kayıtları seçmek (filtreleme), toplam ve ortalama almak (özetleme), en yüksek değerli kaydı bulmak (maksimum arama) ve kayıtları bölüm gibi bir alana göre ayırıp saymak (gruplama).

Bu sayfadaki kod hücreleri kendiliğinden çalışmaz. Her hücrede önce çıktıyı tahmin edin, sonra Run Code düğmesine basın. Kodu değiştirip yeniden çalıştırabilir, Start Over ile ilk hâline döndürebilirsiniz.

Bu bölümün kapsamı

NoteSınavda sorulur
  • liste[indeks]["alan"] erişiminin iki adımı
  • Filtreleme kalıbı ve append()in kaydı kopyalamaması
  • Kayıtlar üzerinde sayma ve biriktirme ile özet çıkarma
  • Maksimum aramada en büyük değerin ait olduğu kaydı tutma
  • Sözlük anahtarlarıyla gruplama
  • Metin alanlarını normalleştirmenin gruplama sonucunu nasıl değiştirdiği
  • Eksik alan için varsayılan değeri problemin kuralına göre seçme
  • Veri çerçevesi (tablo biçiminde veri tutan yapı) kullanan kütüphaneler
  • İkiden çok seviyeli iç içe yapıların derin kopyası (içteki nesnelerin de kopyalanması)

Bu başlıklar konunun devamıdır. İleride karşınıza çıkar, ama bu derste ezberlemeniz beklenmiyor.

Kantinin akşam raporunu nasıl hazırlardınız?

Okul kantininde her satış için bir fiş kesiliyor. Fişte ürünün adı, kategorisi ve tutarı yazıyor. Bugünkü fişler şunlar:

Fiş Ürün Kategori Tutar
1 Kalem Kırtasiye 120 TL
2 Su Büfe 15 TL
3 Defter kırtasiye 80 TL
4 Tost Büfe (boş)
5 Silgi KIRTASİYE 30 TL

Kantin sorumlusu her akşam bu fişlerden bir rapor hazırlıyor. Raporda dört şey var:

  1. Kırtasiye fişleri ayrı bir dosyada durur.
  2. Günün toplam satışı ve fiş başına ortalama tutar yazılır.
  3. Günün en büyük satışı yazılır.
  4. Her kategorinin toplam satışı yazılır.

Bu raporu artık bir program hazırlayacak. Programın adımlarını 1. bölümdeki sözde kodla, Türkçe ve madde madde yazın. Sonra adımlarınızı şu beş durumla deneyin:

  1. Kırtasiye dosyasına fişin kendisini mi koydunuz, fotokopisini mi? Dosyadaki Kalem fişinin tutarını 100 TL olarak düzelttiniz. Asıl fiş yığınındaki Kalem fişinde şimdi ne yazıyor?
  2. Kategori sütununda Kırtasiye, kırtasiye ve KIRTASİYE var. Raporunuzun kategori bölümünde kaç ayrı kırtasiye satırı çıkıyor?
  3. Tost fişinin tutarı boş. Toplama ne eklediniz? Ortalamayı hesaplarken bu fişi saydınız mı?
  4. Kantin bir gün hiç açılmadı, hiç fiş yok. Ortalamaya ne yazıyorsunuz?
  5. Müdür “En büyük satış hangi üründü?” diye sordu. Notunuzda bu sorunun cevabı var mı?

Python bilmeniz gerekmiyor: “Her fişe bak, kategorisi kırtasiye ise ayrı dosyaya koy” da bir adım. Adımlarınızı bir kenara yazın. Bölümde her birinin Python’da nasıl yazıldığını göreceğiz. Alıştırmalardan önce listenize döneceğiz.

Liste içinde sözlükler

Bir öğrenci kaydı:

ogrenci = {
    "ad": "Deniz",
    "bolum": "Bilgisayar",
    "puan": 78
}

Birden fazla öğrenciyi bir listede tutarız. Burada dış yapı bir liste, her eleman bir sözlüktür. Sözlükteki her anahtar-değer çifti kaydın bir alanıdır: ad, bolum, puan. Hücrenin son satırı ne yazar?

Python önce listenin 0 numaralı elemanını, yani ilk sözlüğü alır. Sonra o sözlüğün "puan" alanını okur.

Liste içindeki sözlüğe ve sözlük alanına aşamalı erişim.

İç içe kayıtlara erişim

Uzun bir erişimi tek bakışta çözmeye çalışmayın, soldan sağa parça parça okuyun. ogrenciler[1]["puan"] için:

  1. ogrenciler[1] → ikinci öğrenci sözlüğü
  2. ["puan"] → o sözlükteki puan değeri

Hücreye print(ogrenciler[1]["ad"]) satırını ekleyip çalıştırmadan önce ne yazacağını söyleyin.

Kayıtlar üzerinde gezinmek

Döngünün her turunda ogrenci değişkeni listedeki sıradaki sözlüğü gösterir. Hücre kaç satır yazar?

Bu bölümdeki programların çoğu aynı sırayla çalışır:

kayıt listesi
    ↓
her kaydı sırayla al
    ↓
alanlarını oku
    ↓
koşula göre işle

Tahmin et: hangi kayıtlar yazılır?

Hücre hangi ürün adlarını yazar? Önce tahmin edin, sonra çalıştırın.

Koşula uyan kayıtları böyle seçmeye filtreleme denir.

Koşul yalnız stoku 0 olan ürünlerde doğrudur. Defter ve Cetvel yazılır. Yazılan da sözlüğün tamamı değil, yalnız ad alanıdır.

Filtreleme: koşulu sağlayan kayıtları seçmek

Seçilen kayıtları yazdırmak yerine yeni bir listede toplayabiliriz. gecenler listesinde hangi öğrencilerin kaydı bulunur?

gecenler listesine yalnız puanı 60 ve üzeri olan kayıtlar girer.

Veri işleme sürecinde filtreleme, dönüştürme ve özetleme adımlarının ayrımı.

Filtrele, dönüştür ve özetle

Filtrelenen sözlükler kopyalanmaz

9. bölümde gördüğümüz aliasing (iki adın aynı nesneyi göstermesi) burada yine karşımıza çıkıyor. gecenler.append(ogrenci) yeni bir sözlük oluşturmaz. Listeye var olan sözlüğü gösteren bir bağ ekler. Bu bağa referans denir.

Aşağıdaki kod yalnız gecenler listesindeki ilk kaydın puanını değiştiriyor. Son satır ne yazar?

Çıktı 0’dır. gecenler[0] ile ogrenciler[0] aynı sözlük nesnesini gösterir. Bu yüzden gecenler üzerinden yapılan değişiklik ogrenciler listesinden de görünür.

Asıl kaydı değiştirmeden ayrı bir kayıt istiyorsanız listeye sözlüğün sığ kopyasını (shallow copy) ekleyin. Sığ kopya, sözlüğün kendisini kopyalayan ama içindeki değerleri paylaşan kopyadır:

gecenler.append(ogrenci.copy())

Hücrede append(ogrenci) satırını append(ogrenci.copy()) yapıp yeniden çalıştırın. Son satır ne yazar?

Warning

.copy() yalnızca sözlüğün kendisini kopyalar. Sözlüğün içinde liste gibi değiştirilebilir bir değer varsa o değer iki kopya arasında ortak kalır. Bu bölümdeki kayıtlarda değerler yalnızca sayı ve metin olduğu için sığ kopya yeterlidir.

Alıştırma: düşük stok kayıtlarını seçin

Stoku 5 ve altında olan ürünleri dusuk_stok listesine ekleyin. Listede Defter ve Silgi kayıtları bulunmalıdır.

if urun["stok"] <= 5: koşulu içinde dusuk_stok.append(urun) kullanabilirsiniz.

urunler = [
    {"ad": "Kalem", "stok": 12},
    {"ad": "Defter", "stok": 3},
    {"ad": "Silgi", "stok": 5},
    {"ad": "Cetvel", "stok": 8}
]

dusuk_stok = []

for urun in urunler:
    if urun["stok"] <= 5:
        dusuk_stok.append(urun)

print(dusuk_stok)

Özetleme: toplam ve ortalama

Her kaydın aynı alanını bir değişkende toplayabiliriz. Döngünün her turunda bir değişkene ekleyerek toplam tutmaya biriktirme denir. Hücre ne yazar?

Ortalama için toplam / len(satislar) yazabiliriz. Ama liste boşsa len(satislar) sıfır olur ve bölme ZeroDivisionError verir. Bu durumu ayrıca düşünmek gerekir.

Boş liste için ortalama ne döndürmeli?

Boş bir öğrenci listesinde ortalama olarak 0 döndürmek ilk bakışta makul görünebilir. Ama şu iki durum birbirinden farklıdır:

  • []: hiç puan yok.
  • [{"ad": "Ece", "puan": 0}]: bir öğrenci var ve puanı gerçekten 0.

İkisinde de 0 döndürürsek aradaki fark kaybolur. Bu yüzden fonksiyonun sözleşmesine (7. bölümde gördüğümüz, fonksiyonun ne alıp ne döndüreceğini söyleyen yazılı not) boş liste için ayrı bir kural koyuyoruz:

Çıktı:
- liste boşsa None: hesaplanabilecek ortalama yok
- değilse puanların sayısal ortalaması

Fonksiyonu çağıran kod bu durumu kontrol eder. Hücre ne yazar? Sonra puan_ortalamasi([]) çağrısını puan_ortalamasi([{"ad": "Ece", "puan": 0}]) yapıp yeniden çalıştırın.

Note

None değerini ve is None kontrolünü 6. bölümde gördük. Bir fonksiyonun sorunu None döndürerek bildirmesinin artılarını ve eksilerini 13. bölümde konuşacağız. Bu bölümde şu kural yeter: veri yoksa sonuç bir sayı olmamalı.

Maksimum arama: yalnızca değeri değil, kaydı bulmak

9. bölümde bir sayı listesinde “şimdiye kadarki en yüksek” değeri tutan kalıbı gördük. Kayıtlarda aynı kalıpla en yüksek puanın ait olduğu sözlüğü buluruz. Hücre ne yazar?

Fonksiyon Ayşe’nin kaydını, yani {'ad': 'Ayşe', 'puan': 92} sözlüğünü döndürür. en_yuksek her güncellendiğinde sayının değil, kaydın tamamının yerini alır. Bu yüzden sonuçta ad da vardır.

14. bölümde “en çok ciro yapan ürün”ü bulurken de bu kalıbı kullanacağız.

Important

max() bir sayı listesindeki en büyük değeri tek satırda bulur. Veri sözlüklerden oluşuyorsa başlangıçta döngüyü kendiniz yazın. Böylece hangi alanın karşılaştırıldığını ve hangi kaydın tutulduğunu kodda açıkça görürsünüz.

Alıştırma: toplam stok fonksiyonu

Döngüde her ürünün stok değerini toplama ekleyin. Beklenen sonuç 20’dir.

Döngü içinde toplam = toplam + urun["stok"] yazabilirsiniz.

def toplam_stok(urunler):
    toplam = 0

    for urun in urunler:
        toplam = toplam + urun["stok"]

    return toplam

Basit gruplama

Kayıtları bir alana göre gruplamak için sözlük kullanırız. Aşağıdaki kod her bölümde kaç öğrenci olduğunu sayar: bölüm adı anahtar, öğrenci sayısı değer olur. Hücre ne yazar?

10. bölümde bir listedeki şehirlerin kaç kez geçtiğini (frekansını) böyle saymıştık. Burada aynı kalıbı kayıtların bir alanına uyguluyoruz. Bir bölüm ilk kez geldiğinde sözlükte henüz yoktur ve get(bolum, 0) 0 döndürür.

Gruplama anahtarı gerçekten aynı mı?

Metin alanlarını anahtar yaptığımızda "Siber", "siber" ve " Siber " sözlük için üç ayrı anahtardır. Aşağıdaki sözlükte kaç anahtar olur?

Üç yazım aynı bölümü anlatıyorsa önce hepsini aynı biçime getiren açık bir kural koymalısınız. Buna normalleştirme denir. anahtar = bolum satırını şöyle değiştirip yeniden çalıştırın:

anahtar = bolum.strip().lower()

Veride Türkçe harf yoksa bu yeterli olabilir. Ama 8. bölümde gördüğümüz gibi lower(), Türkçe I ve İ harflerini Türkçe kurala göre küçültmez: "KIRTASİYE".lower() sonucu "kırtasiye" olmaz. "İdari" ile "IDARI" gibi yazımların aynı sayılıp sayılmayacağına siz karar verirsiniz.

Warning

Gruplamadan önce “biraz temizleyelim” diye her değere körlemesine lower() uygulamayın. Hangi yazımların aynı sayılacağına siz karar vermelisiniz. Türkçe ad, bölüm, ürün ve şehir adlarında 8. bölümdeki normalleştirme uyarısını hatırlayın.

Her grubun toplamını bulmak

Aynı kalıpla her grubun kayıt sayısı yerine tutarlarının toplamını da tutabiliriz. Hücre ne yazar?

Sayarken get() sonucuna 1, toplarken kaydın tutar alanı eklenir. Geri kalan her şey aynıdır.

Eksik alan ve get()

Bir kayıtta bir alan hiç bulunmayabilir. Aşağıdaki hücrede iki satırdan hangisi hata verir?

İlk satır 0 yazar. İkinci satır KeyError: 'stok' verir, çünkü köşeli parantezle olmayan bir anahtar okunamaz.

get()’in ikinci argümanı, alan yoksa döndürülecek değerdir. Buna varsayılan değer denir. urun.get("stok", 0) hata vermez, 0 döndürür. Ama bu ancak stok bilgisi olmayan ürünün stoku gerçekten sıfır sayılıyorsa doğrudur.

Başka bir problemde eksik alan, verinin hatalı girildiğini gösterebilir. Tutarı yazılmamış bir satış fişine 0 koyarsanız fiş ortalamaya girer ve ortalamayı düşürür. Program hata vermeden yanlış sonuç verir.

Important

get() hatayı önler ama doğru varsayılan değeri sizin yerinize seçmez. Eksik alanın sizin probleminizde ne anlama geldiğine bakıp onu siz seçersiniz. Program hata vermedi diye veri doğru işlenmiş olmaz.

Veri işleme akışını parçalamak

Küçük bir veri problemine şu sırayla yaklaşabilirsiniz:

veriyi tanı
    ↓
hangi kayıtlar gerekli?
    ↓
hangi alanlar kullanılacak?
    ↓
filtrele / say / biriktir / maksimumu bul / grupla
    ↓
sonucu açık bir yapıda döndür

Bütün bu adımları tek bir fonksiyona yığmayın. İşi gecen_ogrenciler, puan_ortalamasi ve en_yuksek_puanli gibi, her biri tek iş yapan fonksiyonlara bölün. Böylece her parçayı ayrı ayrı deneyebilirsiniz.

Soruya dönelim: kantin raporu Python’da

Bölümün başında kantin raporunun adımlarını yazıp beş durumla denemiştiniz. Python’daki karşılıkları şöyle:

Durum Sözde kodda Python’da Dikkat
Bir fişin tutarını okumak “3. fişin tutar sütununa bak” fisler[2]["tutar"] Önce kayıt, sonra alan seçilir. İndeks 0’dan başlar
Kalem fişini düzeltmek “Kırtasiye fişlerini ayrı dosyaya koy” kirtasiye.append(fis) append() fişin kendisini koyar, fotokopisini almaz. Dosyadaki fişi düzeltirseniz asıl listedeki fiş de değişir. Fotokopi için fis.copy()
Üç ayrı kırtasiye yazımı “Kategorisi aynı olan fişleri topla” toplamlar[kategori] = toplamlar.get(kategori, 0) + tutar Normalleştirme yoksa üç ayrı satır çıkar. strip().lower() boşluk ve büyük harf farkını giderir, ama KIRTASİYE’yi kırtasiye yapmaz
Tutarı boş Tost fişi “Tutar yoksa 0 say” fis.get("tutar", 0) 0 koyarsanız fiş sayılır ve ortalama düşer. Fişi ortalamaya katıp katmayacağınıza siz karar verirsiniz
Hiç fiş yok “Fiş yoksa ortalama yazma” if len(fisler) == 0: return None 0 döndürürseniz “satış yok” ile “ortalama 0 TL” ayrımı kaybolur. Kontrol yoksa bölme ZeroDivisionError verir
En büyük satış hangi ürün? “En büyük tutarı not al” en_buyuk = fis Yalnız tutarı tutarsanız ürünün adı kaybolur. Kaydın tamamı tutulur

Listenizi tabloyla karşılaştırın. Kırtasiye dosyası için “fotokopi” yazmadıysanız Python da fotokopi almaz: append() fişin kendisini ekler. Kategori sütunundaki üç yazımı tek satırda toplamak için yazdığınız bir kural yoksa program da onları ayrı sayar.

Değiştir: rapora yeni alan ekleyin

Aşağıdaki kod her kayda gecti adında yeni bir alan ekliyor. Çalıştırmadan önce son satırın ne yazacağını söyleyin.

Bu kod listedeki sözlüklerin kendisini değiştirir, kopya almaz. Bu kayıtları daha önce gecenler.append(ogrenci) ile başka bir listeye eklemiş olsaydınız yeni gecti alanını o listede de görürdünüz. Asıl veri değişmemeliyse ogrenci.copy() ile kopya alıp onu değiştirin ya da her kayıt için yeni bir sözlük oluşturun.

Kodu, gecti yerine durum adında bir alan ekleyecek biçimde değiştirin: puanı 60 ve üzeriyse "geçti", değilse "kaldı" olsun.

Üret: kantinin kategori toplamları

Bölümün başındaki kantin raporunun dördüncü işini yazın. kategori_toplamlari fonksiyonu her kategorinin toplam satışını bir sözlükte döndürmeli. Kategori adları farklı yazılmış olabilir: anahtarı oluşturmadan önce strip() ve lower() ile normalleştirin. Bu verideki kategorilerde I ya da İ harfi yok, bu yüzden lower() yeterli.

Beklenen sonuç iki anahtarlı bir sözlüktür: kırtasiye için 230, büfe için 75.

Döngü içinde önce kategori = fis["kategori"].strip().lower() yazın. Sonra toplamlar[kategori] = toplamlar.get(kategori, 0) + fis["tutar"] kullanın.

def kategori_toplamlari(fisler):
    toplamlar = {}

    for fis in fisler:
        kategori = fis["kategori"].strip().lower()
        toplamlar[kategori] = toplamlar.get(kategori, 0) + fis["tutar"]

    return toplamlar

Sınav provası

Önce kendi cevabınızı seçin, sonra cevap anahtarında her şıkkın neden doğru ya da yanlış olduğunu okuyun. Yanlış şıklar rastgele yazılmadı; bu konuda öğrencilerin gerçekten yaptığı hatalardan seçildi. Sınav soruları da aynı yolla hazırlanır.

Madde 1. ogrenciler bir sözlük listesiyken ogrenciler[2]["puan"] ifadesi ne yapar?

  • A. puan adlı listenin 2 numaralı elemanını verir
  • B. Önce listenin 2 numaralı kaydını seçer, sonra o kaydın puan alanını okur
  • C. Üçüncü kaydı siler
  • D. Listenin 2 numaralı elemanını puan değeriyle değiştirir
  • E. Bütün kayıtların puan alanlarını toplar

Madde 2. gecenler.append(ogrenci) satırı neden yeni bir sözlük kopyası oluşturmaz?

  • A. append() yalnızca sayıları kopyalar
  • B. append() aynı sözlüğe bir referans ekler
  • C. Kopya oluşur ama bellekte aynı yerde tutulur
  • D. Kopya oluşur; iki liste bağımsızdır
  • E. Sözlükler değiştirilemez olduğu için kopyalanmaz

Madde 3. 50 ve üzeri puan alan öğrencileri yeni bir listede toplamak için boşluğa ne gelmelidir?

gecenler = []

for ogrenci in ogrenciler:
    if ogrenci["puan"] >= 50:
        ______
  • A. gecenler.append(ogrenci)
  • B. gecenler = ogrenci
  • C. ogrenciler.remove(ogrenci)
  • D. print(ogrenci)
  • E. gecenler.append(ogrenci["puan"])

Madde 4. Aşağıdaki program ne yazdırır?

kayitlar = [
    {"ad": "Ali", "puan": 70},
    {"ad": "Ayşe", "puan": 40},
    {"ad": "Can", "puan": 90},
]

toplam = 0
for kayit in kayitlar:
    toplam = toplam + kayit["puan"]

print(toplam / len(kayitlar))
  • A. 66.66666666666667
  • B. Hata verir; sözlük alanları toplanamaz
  • C. 200
  • D. 66
  • E. 3

Madde 5. En yüksek puanlı öğrenciyi bulurken yalnızca en yüksek sayıyı değil, kaydın kendisini tutmak neden gerekir?

  • A. Gerekmez; sonradan puana göre arama yapılabilir
  • B. max() fonksiyonu sözlüklerle çalışmadığı için
  • C. Böylece döngü daha hızlı biter
  • D. Sayılar listede tutulamadığı için
  • E. Sayı tek başına puanı kimin aldığını söylemez

Madde 6. Bölüm başına öğrenci sayısını tutmak için hangi yapı uygundur?

  • A. Tek bir sayaç değişkeni
  • B. Demet; değerler değişmeyeceği için
  • C. Sözlük; bölüm adı anahtar, sayı değer olur
  • D. Küme; her bölüm bir kez tutulur
  • E. Liste; her bölüm için bir eleman eklenir

Madde 7. Türkçe metin alanlarında lower() ile körlemesine gruplama yapmak neden sorun çıkarabilir?

  • A. Gruplama yalnızca sayısal alanlarda yapılabilir
  • B. Sorun çıkarmaz; lower() bütün dillerde aynı çalışır
  • C. lower() Türkçe karakterleri tümüyle siler
  • D. I ve İ dönüşümü yüzünden aynı değer iki gruba düşebilir
  • E. lower() sözlüklerde kullanılamaz

Madde 8. Eksik bir alanı 0 kabul etmek hangi durumda yanlış olur?

  • A. Alan sayısal olduğunda her zaman yanlıştır
  • B. Yalnızca metin alanlarında yanlış olur
  • C. Değer hiç ölçülmemişse ve hesaba katılacaksa
  • D. Yanlış olmaz; 0 güvenli bir varsayılandır
  • E. 0 hiçbir zaman geçerli bir değer olamaz

Madde 1. Doğru: B. İki erişim art arda yapılır: ilk köşeli parantezde indeks, ikincisinde anahtar vardır.

  • A yanlış: Erişim sağdan sola okunursa puan bir liste gibi görünür. Ama ifade soldan sağa çözülür: ilk köşeli parantez ogrenciler listesine aittir.
  • C yanlış: 2 numaralı indeksin üçüncü kayda denk geldiğini bilen öğrenci bu kayda bir işlem yapıldığını düşünebilir. Ama erişim hiçbir şeyi silmez; silmek için remove() ya da pop() gerekir.
  • D yanlış: Köşeli parantez atamada da kullanıldığı için ifade bir değeri yerleştiriyormuş gibi okunabilir. Ama = yok; değer yalnızca okunuyor.
  • E yanlış: "puan" bütün kayıtlarda bulunan bir alan olduğu için hepsine birden bakıldığı sanılabilir. Ama [2] tek bir kayıt seçer ve yalnız onun alanı okunur.

Madde 2. Doğru: B. append() kaydın kopyasını değil, o kayda giden referansı ekler; iki liste aynı sözlüğü paylaşır. Filtrelenmiş listedeki bir kaydı değiştirirseniz ilk listedeki kayıt da değişir. Bağımsız kayıt gerekiyorsa ogrenci.copy() kullanılır.

  • A yanlış: Sayılarla çalışırken paylaşım fark edilmediği için böyle sanılabilir. Ama append() hiçbir türü kopyalamaz; her zaman referans ekler.
  • C yanlış: İki listenin aynı kaydı göstermesini açıklamaya çalışır, bu yüzden akla yatkın gelir. Ama kopya hiç oluşmaz; tek bir sözlük vardır.
  • D yanlış: İki liste gerçekten ayrı nesnelerdir, bu yüzden içleri de bağımsız sanılır. Ama içlerindeki kayıtlar ortaktır.
  • E yanlış: Kopyalanmayan şeyin değişmez olduğu düşünülebilir. Ama sözlük değiştirilebilirdir ve copy() ile kopyalanabilir.

Madde 3. Doğru: A. Filtreleme kalıbı budur: koşulu sağlayan kayıt yeni listeye eklenir.

  • B yanlış: Atama bir değeri değişkene koyduğu için kaydı listeye koyuyormuş gibi görünür. Ama bu satır gecenler adını tek bir kayda bağlar; her turda bir önceki kaydın yerini alır ve liste dolmaz.
  • C yanlış: Kalanları seçmek yerine geçemeyenleri atmak da aynı sonuca götürecek gibi görünür. Ama burada istenen yeni bir listeyi doldurmak. Üstelik üzerinde dolaşılan listeden silmek eleman atlamalarına yol açar.
  • D yanlış: Seçilen kayıtları ekrana yazan döngüler sık görüldüğü için bu satır tanıdık gelir. Ama yazdırmak ekrana çıktı verir, gecenler listesi boş kalır.
  • E yanlış: Koşulda puana bakıldığı için listeye de puanın eklenmesi doğal gelir. Ama listeye yalnızca puanlar girer; kaydın adı ve öteki alanları kaybolur.

Madde 4. Doğru: A. Toplam 200, kayıt sayısı 3’tür. / işlemi float sonuç verir.

  • B yanlış: Sözlüklerin kendisi toplanamadığı için alanlarının da toplanamayacağı sanılabilir. Ama kayit["puan"] bir sayıdır ve sayılar toplanır.
  • C yanlış: Döngü toplamı hesapladığı için son satırın da toplamı yazdığı sanılabilir. Ama print() toplamı len(kayitlar) ile bölüyor; 200 yalnız ara sonuçtur.
  • D yanlış: Puanlar tam sayı olduğu için sonucun da tam sayı olacağı düşünülebilir. Ama / tam bölme yapmaz, her zaman float verir; tam sayı sonucu için // gerekirdi.
  • E yanlış: len(kayitlar) son satırda göze çarptığı için yazılan değer o sanılabilir. Ama 3 yalnız bölendir; sonuç toplamın 3’e bölümüdür.

Madde 5. Doğru: E. Ad da gerekiyorsa kaydın kendisi saklanmalıdır. Kalıpta en büyük değer her değiştiğinde o değerin ait olduğu kayıt da güncellenir.

  • A yanlış: Sayı bulunduktan sonra listede o puanı aramak da adı verecek gibi görünür. Ama aynı puanı birden fazla öğrenci almış olabilir; sonradan arama yapılırsa hangi öğrencinin kastedildiği belirsiz kalır ve liste ikinci kez taranır.
  • B yanlış: max(kayitlar) doğrudan yazılınca hata verdiği için akla yatkın gelir. Ama max() uygun bir ölçütle sözlük listelerinde de kullanılabilir; gerekçe bu değildir.
  • C yanlış: Daha çok bilgi tutmanın bir kazanç getirdiği düşünülebilir. Ama döngünün tur sayısı değişmez.
  • D yanlış: Kayıt listesinde sayılar sözlüklerin içinde durduğu için böyle sanılabilir. Ama sayılar listede tutulabilir.

Madde 6. Doğru: C. Grup adı doğrudan anahtar olabildiği için her grubun sayısına adıyla erişilir.

  • A yanlış: Saymak denince akla ilk sayac = sayac + 1 kalıbı gelir. Ama tek sayaç toplam öğrenci sayısını verir; bölüm ayrımı yapmaz.
  • B yanlış: Bölüm adları sabit olduğu için değişmeyen bir yapı uygun görünebilir. Ama sayaçlar her kayıtta güncellenir; demet değiştirilemez.
  • D yanlış: Gruplamada her bölüm bir kez görünmeli, kümede de her değer bir kez bulunur. Ama küme hangi bölümlerin olduğunu söyler, kaç öğrenci olduğunu tutmaz.
  • E yanlış: Bu bölümde kayıtlar hep listede tutulduğu için sayaçların da listeye gireceği düşünülebilir. Ama listede hangi sayının hangi bölüme ait olduğu kaybolur.

Madde 7. Doğru: D. Türkçeye özgü I ve İ dönüşümü genel harf dönüşümüyle aynı sonucu vermez. "İĞNE" ile "iğne", lower() uygulandıktan sonra bile eşleşmeyebilir. casefold() de bunu tek başına çözmez.

  • A yanlış: Sayma ve toplama örnekleri sayılarla yapıldığı için böyle sanılabilir. Ama metin alanlarında da gruplama yapılır.
  • B yanlış: İngilizce metinlerde lower() sorunsuz çalıştığı için akla yatkın gelir. Ama Türkçedeki noktalı ve noktasız i ayrımı bu varsayımı bozar.
  • C yanlış: Bazı Türkçe harflerde çıktı beklenmedik göründüğü için silindiği sanılabilir. Ama karakterler silinmez; yalnızca belirli bir harf çiftinde beklenen dönüşüm olmaz.
  • E yanlış: Kayıtlar sözlük olduğu için sorunun burada olduğu düşünülebilir. Ama lower() sözlüğün metin alanlarına uygulanabilir; sorun dönüşümün kendisindedir.

Madde 8. Doğru: C. 0, eksik değeri geçerli bir ölçüm gibi gösterir ve ortalamayı düşürür. Girilmemiş bir puanla sıfır alınmış bir puan farklı şeylerdir. Seçilen varsayılan değer sonucu doğrudan değiştirir.

  • A yanlış: Sorun gerçekten sayısal alanlarda çıktığı için genelleme cazip gelir. Ama bazı problemlerde 0 doğru varsayılandır; örneğin hiç satış yapılmamış bir gün.
  • B yanlış: Metin alanına 0 yazmak tuhaf durduğu için akla gelebilir. Ama sorun en çok sayısal alanlarda ortaya çıkar, çünkü 0 hesaba katılır.
  • D yanlış: 0 programı durdurmadığı için güvenli görünür. Ama eksik veriyi hata vermeden hesaba katar ve sonucu bozar.
  • E yanlış: 0 sık sık “boş” anlamında kullanıldığı için böyle sanılabilir. Ama çoğu alanda geçerli bir değerdir; sorun, eksik veriyle karışmasıdır.

Tek sayfa özet

  • Bir kaydı sözlükte, kayıtların hepsini bir listede tutarız.
  • liste[indeks]["alan"] önce kaydı, sonra alanı seçer.
  • Filtreleme, koşulu sağlayan kayıtları yeni bir listeye eklemektir. append(ogrenci) sözlüğü kopyalamaz; iki liste aynı sözlüğü paylaşır.
  • Ayrı bir kayıt gerekiyorsa ogrenci.copy() kullanılır. Değerleri sayı ve metin olan kayıtlar için bu sığ kopya yeterlidir.
  • Özetlemede bir alanın değerleri sayılır ya da toplanır.
  • Liste boşsa None döndürmek, “veri yok” durumunu gerçekten 0 olan bir sonuçtan ayırır.
  • Maksimum aramada en büyük sayıyla birlikte o sayının ait olduğu kayıt da tutulabilir.
  • Gruplamada grup adı sözlüğün anahtarı, sayı ya da toplam ise değeri olur.
  • Metin alanlarında gruplamanın sonucu seçilen normalleştirme kuralına bağlıdır. strip().lower() boşluk ve büyük harf farkını giderir, ama Türkçe I ve İ harflerini Türkçe kurala göre küçültmez.
  • get(grup, 0) bir grubun sayacını ya da toplamını başlatmak için kullanışlıdır. Eksik bir alanın varsayılan değerini ise o alanın probleminizde ne anlama geldiği belirler: tutarı boş bir fişe 0 yazmak ortalamayı düşürür.
  • Veri işleme kodunu tek iş yapan küçük fonksiyonlara bölerseniz her parçayı ayrı ayrı sınayabilirsiniz.
  • Kantin raporundaki her adım bu kalıplardan biridir: fişleri ayırmak filtreleme, toplam ve ortalama özetleme, en büyük satış maksimum arama, kategori toplamları gruplamadır.

Bir sonraki bölümde bu kayıtları bir dosyadan okuyacak, sonuçları dosyaya yazacağız: konu dosyalar ve CSV.

Bu bölümün kazanımları

Bu bölümü bitiren öğrenci:

  • liste[indeks]["alan"] erişimini iki adımda çözümler.
  • Filtreleme kalıbını kurar ve append()in kaydı kopyalamadığını açıklar.
  • Kayıtlar üzerinde sayma ve biriktirmeyle özet çıkarır.
  • Maksimum aramada en büyük değerle birlikte o değerin ait olduğu kaydı tutar.
  • Sözlük anahtarlarıyla gruplama yapar.
  • Metin alanlarında normalleştirme kuralının gruplama sonucunu belirlediğini açıklar.
  • Eksik alan için varsayılan değeri problemin kuralına göre seçer.
Back to top