8 İç İçe Döngüler, while Döngüsü ve match-case
Bir önceki bölümde bir listenin elemanları üzerinde for döngüsüyle dolaştık. Bazı problemlerde ise iki şey birden dolaşılır: bir tablonun satırları ve her satırın sütunları, ya da bir sayı aralığı ve her sayının bölen adayları. Bunun için bir döngünün içine ikinci bir döngü yazılır.
Bazı tekrarların sayısı ise önceden belli değildir: kullanıcı doğru sayıyı bulana kadar tahmin almak, ya da geçerli bir değer girene kadar soruyu yeniden sormak gibi. Bu tür işler için bir koşul doğru olduğu sürece dönen while döngüsü kullanılır. Bölümün sonunda, bir değişkenin değerine göre çok sayıda durum arasından seçim yapmayı kolaylaştıran match-case yapısını göreceğiz.
8.1 İç İçe Döngüler
Bir döngünün bloğunun içine başka bir döngü yazılabilir; böylece dıştaki döngünün her yinelemesinde içteki döngü baştan sona bir kez çalışır.
Tanım 8.1 (İç İçe Döngü)
for dis_degisken in dis_koleksiyon:
for ic_degisken in ic_koleksiyon:
içteki döngüde yapılacak işlemler
yapısına iç içe döngü (nested loop) denir. Dıştaki döngünün her yinelemesinde içteki döngü bütün elemanlarını dolaşır. Dıştaki döngü \(m\), içteki döngü \(n\) kez dönüyorsa içteki blok toplam \(m \cdot n\) kez çalışır.
Yani iç içe döngü bir saatin akrep ve yelkovanı gibi çalışır: yelkovan (içteki döngü) tam bir tur attığında akrep (dıştaki döngü) bir adım ilerler.
for i in range(3):
for j in range(2):
print(f"Dış döngü: {i}, İç döngü: {j}")Dış döngü: 0, İç döngü: 0
Dış döngü: 0, İç döngü: 1
Dış döngü: 1, İç döngü: 0
Dış döngü: 1, İç döngü: 1
Dış döngü: 2, İç döngü: 0
Dış döngü: 2, İç döngü: 1
Dıştaki döngü \(3\), içteki \(2\) kez döndüğü için içteki print \(3 \cdot 2 = 6\) kez çalıştı. i her değerini alırken j baştan başlayıp \(0\) ve \(1\) değerlerini aldı.
İçteki döngünün aralığı, dıştaki döngünün değişkenine bağlı da olabilir. Aşağıdaki programda \(i\). satırda \(i + 1\) yıldız yazılır:
for i in range(5):
for j in range(i + 1):
print("*", end=" ")
print()*
* *
* * *
* * * *
* * * * *
İçteki döngü yıldızları end=" " ile aynı satıra yazar; dıştaki döngünün bloğundaki boş print() ise her satırın sonunda yeni satıra geçer. Girintiye dikkat edin: print() içteki döngünün değil, dıştaki döngünün içindedir.
Örnek 8.1 (Çarpım Tablosu) \(1\)’den \(5\)’e kadar sayıların çarpım tablosunu hizalı bir tablo olarak yazdırınız.
Çözüm
Dıştaki döngü satırları, içteki döngü sütunları dolaşır; \(i\). satırın \(j\). sütununa \(i \cdot j\) yazılır. Sayıların hizalı durması için her çarpımı f-string’in :4 biçim belirteciyle dört karakterlik bir alana sağa yaslı olarak yazarız:
for i in range(1, 6):
for j in range(1, 6):
print(f"{i * j:4}", end="")
print() 1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
Tablo köşegene göre simetriktir, çünkü \(i \cdot j = j \cdot i\)’dir. \(\blacksquare\)
İç İçe Döngülerde break ve continue
İç içe döngülerde break ve continue yalnız içinde bulundukları döngüyü etkiler.
İçteki döngüde çalışan bir break yalnız içteki döngüyü bitirir; dıştaki döngü bir sonraki yinelemesiyle devam eder.
for i in range(3):
for j in range(3):
if j == 1:
break
print(f"i: {i}, j: {j}")i: 0, j: 0
i: 1, j: 0
i: 2, j: 0
Her i için içteki döngü j = 0’ı yazdı, j = 1’de bitti; ama dıştaki döngü durmadı. continue kullanılsaydı yalnız j = 1 atlanırdı:
for i in range(3):
for j in range(3):
if j == 1:
continue
print(f"i: {i}, j: {j}")i: 0, j: 0
i: 0, j: 2
i: 1, j: 0
i: 1, j: 2
i: 2, j: 0
i: 2, j: 2
Matrisler Üzerinde Dolaşmak
Elemanları da birer liste olan bir liste, satırları ve sütunları olan bir tabloyu, yani bir matrisi temsil eder; matrisin elemanları iç içe bir döngüyle dolaşılır.
matris = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] listesinde matris[0] birinci satırdır, matris[1][2] ikinci satırın üçüncü elemanı, yani \(6\)’dır. Dıştaki döngü satırları, içteki döngü bir satırın elemanlarını dolaşır:
matris = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for satir in matris:
for eleman in satir:
print(eleman, end=" ")
print()
print(matris[1][2])1 2 3
4 5 6
7 8 9
6
İçteki döngüye bir koşul eklenerek belli elemanlar seçilebilir; enumerate ise satır ve sütun numaralarını da verir.
matris = [[1, 24, 3], [4, 5, 6], [7, 18, 9]]
for i, satir in enumerate(matris):
for j, eleman in enumerate(satir):
if eleman % 2 == 0:
print(f"Satır {i}, sütun {j}: {eleman} çift bir sayıdır.")Satır 0, sütun 1: 24 çift bir sayıdır.
Satır 1, sütun 0: 4 çift bir sayıdır.
Satır 1, sütun 2: 6 çift bir sayıdır.
Satır 2, sütun 1: 18 çift bir sayıdır.
Örnek 8.2 (İki Listenin Bütün Çiftleri) Aşağıdaki programın çıktısını bulunuz.
birinci = []
ikinci = []
for x in [2, 3, 4]:
for y in [3, 4, 7]:
birinci.append(x + y)
ikinci.append(x * y)
print("birinci:", birinci)
print("ikinci:", ikinci)Çözüm
Dıştaki döngünün her x değeri için y sırayla \(3\), \(4\), \(7\) olur; toplam \(3 \cdot 3 = 9\) çift vardır. x = 2 için toplamlar \(5, 6, 9\), çarpımlar \(6, 8, 14\); x = 3 için toplamlar \(6, 7, 10\), çarpımlar \(9, 12, 21\); x = 4 için toplamlar \(7, 8, 11\), çarpımlar \(12, 16, 28\)’dir.
birinci = []
ikinci = []
for x in [2, 3, 4]:
for y in [3, 4, 7]:
birinci.append(x + y)
ikinci.append(x * y)
print("birinci:", birinci)
print("ikinci:", ikinci)birinci: [5, 6, 9, 6, 7, 10, 7, 8, 11]
ikinci: [6, 8, 14, 9, 12, 21, 12, 16, 28]
\(\blacksquare\)
8.2 while Döngüsü
for döngüsü bir koleksiyonun elemanları bitince durur; while döngüsü ise bir koşul doğru olduğu sürece döner.
Tanım 8.2 (while Döngüsü)
while koşul:
koşul doğru olduğu sürece çalışacak komutlar
yapısında önce koşul denetlenir. Koşul True ise girintili komutlar çalışır ve koşul yeniden denetlenir; bu, koşul False olana kadar sürer. Koşul ilk denetlemede False ise blok hiç çalışmaz.
Yani while “koşul sağlandıkça tekrarla” demektir. Döngünün bir gün bitmesi için bloğun içinde koşulu eninde sonunda False yapacak bir değişiklik bulunmalıdır; genellikle bu, koşulda kullanılan bir sayacın artırılmasıdır.
while döngüsünün akışı. Koşul her yinelemeden önce yeniden denetlenir; doğru olduğu sürece blok çalışır ve akış koşula geri döner. Koşul yanlış çıktığında döngüden çıkılır.sayi = 1
while sayi <= 5:
print(sayi)
sayi += 1
print("Döngüden sonra sayi =", sayi)1
2
3
4
5
Döngüden sonra sayi = 6
sayi \(5\) iken blok son kez çalıştı ve sayi’yı \(6\) yaptı. \(6 \le 5\) yanlış olduğu için döngü bitti; döngüden sonra sayi’nın değeri \(6\)’dır.
Örnek 8.3 (Bir while Döngüsünü İzlemek) Aşağıdaki programın çıktısını bulunuz.
sayac = 0
toplam = 0
while sayac <= 10:
sayac = sayac + 2
print("sayac:", sayac)
toplam = toplam + sayac
print("toplam:", toplam)Çözüm
Koşul, sayaç artırılmadan önce denetlenir. sayac \(0, 2, 4, 6, 8, 10\) iken koşul doğrudur ve blok çalışır; her seferinde önce sayac \(2\) artar, sonra yazılır ve toplama eklenir. sayac \(10\) iken blok son kez çalışır ve sayac’ı \(12\) yapar; \(12 \le 10\) yanlış olduğundan döngü biter. Toplam \(2 + 4 + 6 + 8 + 10 + 12 = 42\)’dir.
sayac = 0
toplam = 0
while sayac <= 10:
sayac = sayac + 2
print("sayac:", sayac)
toplam = toplam + sayac
print("toplam:", toplam)sayac: 2
sayac: 4
sayac: 6
sayac: 8
sayac: 10
sayac: 12
toplam: 42
\(12\)’nin de yazılıp toplama eklenmesi şaşırtıcı görünebilir: koşul ancak bir sonraki denetlemede, yani blok bittikten sonra yeniden sorulur. \(\blacksquare\)
Bir for döngüsüyle yapılan her iş, sayacı kendimiz yöneterek bir while döngüsüyle de yapılabilir. \(1\)’den \(100\)’e kadar sayıların toplamı şöyle hesaplanır:
toplam = 0
i = 1
while i <= 100:
toplam = toplam + i
i = i + 1
print("Sayıların toplamı:", toplam)Sayıların toplamı: 5050
Burada for i in range(1, 101): daha kısa ve hatasızdır; while, tekrar sayısının önceden bilinmediği işlerde gerçekten gerekir.
Bir koleksiyonun elemanları ya da belli bir sayı aralığı dolaşılacaksa for kullanılır: tekrar sayısı baştan bellidir. Döngünün ne zaman biteceği çalışma sırasında ortaya çıkıyorsa, örneğin kullanıcının girdiğine ya da bir hesabın sonucuna bağlıysa, while kullanılır.
while Döngüsünde break ve continue
break ve continue komutları while döngüsünde de for döngüsündeki (Tanım 7.3) gibi çalışır.
sayi = 1
while sayi <= 10:
if sayi == 5:
break
print(sayi, end=" ")
sayi += 1
print()
sayi = 1
while sayi < 10:
sayi += 1
if sayi % 2 != 0:
continue
print(sayi, end=" ")
print()1 2 3 4
2 4 6 8 10
İkinci döngüde sayaç, continue’dan önce artırılıyor. Sayaç continue’dan sonra artırılsaydı, continue artırma satırını da atlardı ve sayaç bir daha hiç değişmezdi. Aşağıdaki programda bu yüzden \(5\) için sayaç ayrıca artırılıyor:
a = 0
while a < 10:
if a == 5:
a += 1
continue
print(a, end=" ")
a += 1
print()0 1 2 3 4 6 7 8 9
if bloğundaki a += 1 satırı silinirse a \(5\)’te takılır: koşul hep doğru kalır, continue her seferinde artırma satırını atlar ve döngü hiç bitmez.
Sonsuz Döngü
Koşulu hiçbir zaman False olmayan bir döngü durmadan çalışır.
Tanım 8.3 (Sonsuz Döngü) Koşulu hiçbir zaman yanlış olmadığı için kendiliğinden bitmeyen döngüye sonsuz döngü denir. while True: yazımı bilerek kurulmuş bir sonsuz döngüdür ve ancak bloğun içindeki bir break ile sona erer.
Yani sonsuz döngü bazen bir hatadır, bazen de bilinçli bir tercih: bitiş koşulu döngünün başında değil ortasında denetlenecekse while True: yazılır ve uygun yerde break kullanılır. Yanlışlıkla bir sonsuz döngü başlatılırsa Colab’da hücrenin solundaki durdurma düğmesine, VS Code’da terminalin durdurma düğmesine basılır ya da terminalde Ctrl + C tuşlanır.
while True:
girdi = input("Çıkmak için 'exit' yazın: ")
if girdi.lower() == "exit":
print("Döngü sonlandırılıyor.")
break
print("Devam ediliyor...")Çıkmak için 'exit' yazın: devam
Devam ediliyor...
Çıkmak için 'exit' yazın: Exit
Döngü sonlandırılıyor.
girdi.lower() metni küçük harflere çevirir; böylece kullanıcı EXIT ya da Exit yazsa da döngü biter. Metinlerin buna benzer başka metotları da vardır: upper() bütün harfleri büyütür, capitalize() yalnız ilk harfi büyük yapar.
Örnek 8.4 (Sayı Tahmin Oyunu) Program \(1\) ile \(100\) arasında bir sayı tutsun. Kullanıcı sayıyı bulana kadar tahmin alsın; her yanlış tahminde “daha büyük” ya da “daha küçük” ipucu versin ve sonunda kaç tahminde bulunduğunu yazsın.
Çözüm
Kullanıcının kaç tahmin yapacağı önceden bilinmediği için while True: ile bir sonsuz döngü kurarız ve doğru tahminde break ile çıkarız. Her tahminde bir sayaç artırılır. Tutulan sayı şimdilik sabit olarak \(45\) seçildi; Rastgele Sayılar bölümünde onu bilgisayara rastgele seçtireceğiz.
tutulan = 45
sayac = 0
print("1-100 arası bir sayı tuttum, tahmin et!")
while True:
sayac += 1
tahmin = int(input("Tahminin: "))
if tahmin > tutulan:
print("Daha küçük bir sayı girmelisin.")
elif tahmin < tutulan:
print("Daha büyük bir sayı girmelisin.")
else:
print("Tebrikler, tuttuğum sayıyı bildin!")
break
print(f"{sayac} tahminde buldun.")1-100 arası bir sayı tuttum, tahmin et!
Tahminin: 50
Daha küçük bir sayı girmelisin.
Tahminin: 25
Daha büyük bir sayı girmelisin.
Tahminin: 37
Daha büyük bir sayı girmelisin.
Tahminin: 43
Daha büyük bir sayı girmelisin.
Tahminin: 46
Daha küçük bir sayı girmelisin.
Tahminin: 44
Daha büyük bir sayı girmelisin.
Tahminin: 45
Tebrikler, tuttuğum sayıyı bildin!
7 tahminde buldun.
Kullanıcı her seferinde kalan aralığın ortasındaki sayıyı tahmin ederse (\(50\), \(25\), \(37\), …), aralık her adımda yarıya iner ve \(1\)–\(100\) arasındaki her sayı en çok \(7\) tahminde bulunur, çünkü \(2^7 = 128 \ge 100\)’dür. \(\blacksquare\)
Aynı oyun bir koşullu while döngüsüyle de yazılabilir: döngü, tahmin tutulan sayıya eşit olmadığı sürece döner. Döngüye ilk kez girebilmek için tahmine başlangıçta, “henüz değer yok” anlamına gelen None değeri verilir.
tutulan = 5
tahmin = None
deneme = 0
while tahmin != tutulan:
tahmin = int(input("Tahmininiz: "))
deneme += 1
if tahmin < tutulan:
print("Daha yüksek bir sayı tahmin edin.")
elif tahmin > tutulan:
print("Daha düşük bir sayı tahmin edin.")
print(f"Tebrikler! {deneme} denemede doğru tahmin ettiniz.")Tahmininiz: 10
Daha düşük bir sayı tahmin edin.
Tahmininiz: 3
Daha yüksek bir sayı tahmin edin.
Tahmininiz: 5
Tebrikler! 3 denemede doğru tahmin ettiniz.
Geçerli Bir Girdi Alana Kadar Sormak
Girdi ve Çıktı İşlemleri bölümünde try-except ile hatalı bir girdiyi yakalayıp bir uyarı yazmıştık; bir while True döngüsüyle birleştirildiğinde program, kullanıcı geçerli değerler girene kadar soruyu yeniden sorar.
while True:
try:
a = float(input("1. sayıyı gir: "))
b = float(input("2. sayıyı gir: "))
print(f"Girdiğiniz sayılar: {a} ve {b}")
print("Toplam =", a + b)
break
except ValueError:
print("Hata: Lütfen geçerli bir sayı girin! Tekrar deneyin.")1. sayıyı gir: a
Hata: Lütfen geçerli bir sayı girin! Tekrar deneyin.
1. sayıyı gir: 85
2. sayıyı gir: b
Hata: Lütfen geçerli bir sayı girin! Tekrar deneyin.
1. sayıyı gir: 5
2. sayıyı gir: 6
Girdiğiniz sayılar: 5.0 ve 6.0
Toplam = 11.0
break, iki dönüşüm de başarılı olduğunda çalışır. Bir dönüşüm hata verirse break’e hiç ulaşılmaz, except bloğu çalışır ve döngü baştan başlar.
Örnek 8.5 (Kullanıcının Girdiği Notların Ortalaması) Kullanıcıdan, q yazana kadar not alan ve sonunda girilen notların ortalamasını yazan bir program yazınız.
Çözüm
Kaç not girileceği bilinmediği için while True: kullanırız. Her girdi önce q ile karşılaştırılır; q değilse sayıya çevrilip toplama eklenir ve not sayısı bir artırılır. Hiç not girilmezse sıfıra bölmemek için sonda adet’i denetleriz.
toplam = 0
adet = 0
while True:
girdi = input("Notu girin (çıkmak için q): ")
if girdi == "q":
break
toplam += float(girdi)
adet += 1
if adet > 0:
print(f"Notların ortalaması: {toplam / adet:.2f}")
else:
print("Hiç not girilmedi.")Notu girin (çıkmak için q): 45
Notu girin (çıkmak için q): 63.5
Notu girin (çıkmak için q): 85
Notu girin (çıkmak için q): 70.56
Notu girin (çıkmak için q): q
Notların ortalaması: 66.02
Girilen notların toplamı \(45 + 63{,}5 + 85 + 70{,}56 = 264{,}06\), ortalaması \(264{,}06/4 = 66{,}015 \approx 66{,}02\)’dir. \(\blacksquare\)
Örnek 8.6 (while ile Fibonacci Dizisi) Fibonacci dizisinin ilk \(15\) terimini bir while döngüsüyle yazdırınız.
Çözüm
Dizinin ardışık iki terimini a ve b değişkenlerinde tutarız. Her adımda a’yı yazarız ve takastaki (Tanım 2.10) gibi bir çoklu atamayla a, b = b, a + b yaparız: yeni a eski b, yeni b ise eski iki terimin toplamı olur.
n = 15
a, b = 0, 1
sayac = 0
while sayac < n:
print(a, end=" ")
a, b = b, a + b
sayac += 1
print()0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
a, b = b, a + b yerine a = b ve b = a + b diye iki ayrı satır yazılsaydı, ikinci satırdaki a zaten değişmiş olurdu ve dizi yanlış çıkardı. \(\blacksquare\)
8.3 match-case Yapısı
Bir değişkenin değerine göre çok sayıda durumdan birinin seçileceği programlarda uzun bir if-elif-else zinciri yazmak yerine match-case yapısı kullanılabilir.
Haftanın gününü sıra numarasından bulan bir program if-elif-else ile şöyle yazılır:
gun = 4
if gun == 1:
print("Pazartesi")
elif gun == 2:
print("Salı")
elif gun == 3:
print("Çarşamba")
elif gun == 4:
print("Perşembe")
elif gun == 5:
print("Cuma")
elif gun == 6:
print("Cumartesi")
elif gun == 7:
print("Pazar")
else:
print("Geçersiz gün numarası")Perşembe
Her satırda gun == yazmak hem uzun hem de hataya açıktır.
Tanım 8.4 (match-case Yapısı)
match deger:
case secenek1:
deger secenek1 ise çalışacak komutlar
case secenek2:
deger secenek2 ise çalışacak komutlar
case _:
hiçbir seçenek tutmazsa çalışacak komutlar
yapısında deger sırayla case satırlarındaki seçeneklerle karşılaştırılır ve eşleşen ilk seçeneğin bloğu çalışır. case _: her değerle eşleşir ve if-elif-else’teki else’in görevini görür. Birden çok seçenek | ile birleştirilebilir: case 6 | 7:. Bu yapı Python 3.10 ile dile eklenmiştir.
Yani match-case, “değer şuysa şunu, buysa bunu yap” listesidir. Burada _, alt çizgi değişkeninde (Tanım 7.4) olduğu gibi “ne olursa olsun” anlamına gelir.
gun = 6
match gun:
case 1:
print("Pazartesi")
case 2:
print("Salı")
case 3:
print("Çarşamba")
case 4:
print("Perşembe")
case 5:
print("Cuma")
case 6 | 7:
print("Hafta sonu")
case _:
print("Geçersiz gün numarası")Hafta sonu
match-case değerleri yalnız eşitlik açısından karşılaştırır. “Yaş \(13\)’ten küçükse” gibi aralık koşulları için if-elif-else daha uygundur.
Örnek 8.7 (Hava Durumuna Göre Öneri) Kullanıcıdan bugünkü hava durumunu (Güneşli, Yağmurlu, Karlı, Rüzgârlı) alıp bir giysi önerisi yazan bir program yazınız. Kullanıcı sözcüğü küçük harfle yazsa da program çalışmalıdır.
Çözüm
Girdiyi capitalize() ile ilk harfi büyük, gerisi küçük olacak biçime getiririz; böylece yağmurlu ya da YAĞMURLU girdileri de Yağmurlu olur ve case seçenekleriyle eşleşir.
hava = input("Bugünkü hava durumu nedir? ").capitalize()
match hava:
case "Güneşli":
print("Güneş kremi sürmeyi unutmayın!")
case "Yağmurlu":
print("Şemsiye almayı unutmayın.")
case "Karlı":
print("Kalın bir mont giyin.")
case "Rüzgârlı":
print("Bir rüzgârlık almanız iyi olur.")
case _:
print("Geçersiz hava durumu girdiniz.")Bugünkü hava durumu nedir? yağmurlu
Şemsiye almayı unutmayın.
\(\blacksquare\)
8.4 Çeşitli Örnekler
Aşağıdaki kısa programların çıktısını önce kâğıt üzerinde, değişkenlerin değerlerini adım adım izleyerek bulmaya çalışın.
Örnek 8.8 (Koşula Bağlı Güncelleme) Aşağıdaki programın çıktısını bulunuz.
a, b, toplam = 0, 5, 20
while a < 5:
if a + b > 6:
toplam = a + b
toplam += 1
print(toplam)
a += 1Çözüm
Döngü a \(0\)’dan \(4\)’e kadar beş kez çalışır. a + b > 6 koşulu a = 0 (\(5\)) ve a = 1 (\(6\)) için yanlıştır; toplam değişmez ve \(20\) yazılır. a = 2, 3, 4 için koşul doğrudur: toplam önce a + b, sonra bir fazlası olur ve sırasıyla \(8\), \(9\), \(10\) yazılır.
a, b, toplam = 0, 5, 20
while a < 5:
if a + b > 6:
toplam = a + b
toplam += 1
print(toplam)
a += 120
20
8
9
10
\(\blacksquare\)
Örnek 8.9 (Tek Sayıların Toplamı) \(1\)’den \(9\)’a kadar tek sayıların toplamını bir while döngüsüyle hesaplayınız ve ara toplamları yazdırınız. Aynı toplamı continue kullanan bir döngüyle de bulunuz.
Çözüm
a’yı \(1\)’den başlatıp her adımda \(2\) artırırsak yalnız tek sayıları dolaşırız. Ara toplamlar \(1\), \(1 + 3 = 4\), \(4 + 5 = 9\), \(16\), \(25\) olur; ardışık tek sayıların toplamlarının tam kare çıkması tesadüf değildir: \(1 + 3 + \cdots + (2k - 1) = k^2\).
toplam = 0
a = 1
while a < 10:
toplam = toplam + a
a = a + 2
print(toplam, end=" ")
print()1 4 9 16 25
İkinci yolda bütün sayıları dolaşır, çiftleri continue ile atlarız. Sayaç, continue’dan önce artırıldığı için döngü takılmaz:
toplam = 0
a = 0
while a < 10:
a = a + 1
if a % 2 == 0:
continue
toplam = toplam + a
print(toplam)25
Aynı fikirle \(1\)’den \(99\)’a kadar tek sayıların toplamı \(50^2 = 2500\) bulunur. \(\blacksquare\)
Örnek 8.10 (Üçün Katlarının Ortalaması) Kullanıcının girdiği bir \(N\) sayısına kadar (dahil) \(3\)’e bölünebilen pozitif sayıların ortalamasını bulan bir program yazınız. \(N = 16\) için ekrana \((3 + 6 + 9 + 12 + 15)/5 = 9{,}0\) yazılmalıdır.
Çözüm
\(N\)’den büyük olmayan en büyük \(3\) katı \(X = N - (N \bmod 3)\)’tür: \(N = 16\) için \(16 - 1 = 15\). Bu sayıdan başlayıp \(3\)’er azaltarak \(0\)’a kadar gideriz; her adımda sayıyı toplama ekler, sayacı artırırız.
N = int(input("Bir sayı girin: "))
X = N - (N % 3)
T = 0
sayac = 0
while X > 0:
T = T + X
X = X - 3
sayac = sayac + 1
print("Ortalama =", T / sayac)Bir sayı girin: 16
Ortalama = 9.0
Kullanıcı \(1\) ya da \(2\) girerse \(X = 0\) olur, döngü hiç çalışmaz ve sayac \(0\) kalır; bu durumda son satır sıfıra bölme hatası verir. Programı bu durumlara karşı korumak için son satırdan önce sayac’ın sıfır olup olmadığına bakan bir if eklenmelidir. \(\blacksquare\)
Örnek 8.11 (while ile Faktöriyel) Aşağıdaki program ne hesaplar? Çıktısını bulunuz.
n = 5
f = 1
i = n
while i >= 1:
f = f * i
i = i - 1
print(f)Çözüm
i, n’den başlayıp \(1\)’e kadar azalır ve her adımda f ile çarpılır: \(f = 5 \cdot 4 \cdot 3 \cdot 2 \cdot 1 = 120\). Program \(n! = 5!\) değerini, çarpanları büyükten küçüğe alarak hesaplar.
n = 5
f = 1
i = n
while i >= 1:
f = f * i
i = i - 1
print(f)120
\(\blacksquare\)
8.5 Alıştırmalar
while döngüsü kurarken her seferinde döngünün bitmesini sağlayan değişikliği bulun.
Alıştırma 8.1 (Rakamlar Toplamı) Bir pozitif tam sayının rakamlarının toplamını metne çevirmeden, % ve // kullanan bir while döngüsüyle bulunuz. \(n = 2026\) için deneyiniz.
Çözüm
Son rakam n % 10 ile alınır, n //= 10 ise son rakamı atar. Bu iki adımı n sıfır olana kadar tekrarlarız. \(2026\) için sırayla \(6\), \(2\), \(0\), \(2\) rakamları alınır ve toplam \(10\) olur.
n = 2026
toplam = 0
while n > 0:
toplam += n % 10
n //= 10
print(toplam)10
Döngü her adımda n’yi küçülttüğü için mutlaka biter. \(\blacksquare\)
Alıştırma 8.2 (Öklid Algoritmasıyla EBOB) \(a\) ve \(b\) pozitif tam sayıları için \(\operatorname{ebob}(a, b) = \operatorname{ebob}(b, a \bmod b)\) ve \(\operatorname{ebob}(a, 0) = a\) eşitliklerini kullanarak \(\operatorname{ebob}(252, 105)\) değerini bir while döngüsüyle bulunuz ve math.gcd ile karşılaştırınız.
Çözüm
b sıfır olmadığı sürece a, b = b, a % b çoklu atamasını yaparız; b sıfır olduğunda EBOB a’dadır. Adımlar:
- \((252, 105)\): \(252 = 2 \cdot 105 + 42\), yeni çift \((105, 42)\).
- \((105, 42)\): \(105 = 2 \cdot 42 + 21\), yeni çift \((42, 21)\).
- \((42, 21)\): \(42 = 2 \cdot 21 + 0\), yeni çift \((21, 0)\).
import math
a, b = 252, 105
while b != 0:
a, b = b, a % b
print(a, b)
print("EBOB:", a, "- math.gcd:", math.gcd(252, 105))105 42
42 21
21 0
EBOB: 21 - math.gcd: 21
\(\blacksquare\)
Alıştırma 8.3 (Bini Aşan İlk İkinin Kuvveti) \(2^k \ge 1000\) olan en küçük \(k\) doğal sayısını bir while döngüsüyle bulunuz.
Çözüm
Kaç adım gerektiği önceden bilinmediği için while uygundur. kuvvet’i \(1 = 2^0\) ile başlatır ve \(1000\)’den küçük olduğu sürece ikiyle çarpıp k’yı artırırız. \(2^9 = 512 < 1000 \le 1024 = 2^{10}\) olduğundan \(k = 10\) bulunmalıdır.
k = 0
kuvvet = 1
while kuvvet < 1000:
kuvvet *= 2
k += 1
print(k, kuvvet)10 1024
\(\blacksquare\)
Alıştırma 8.4 (Sayıyı Tersine Çevirmek) \(n = 12345\) sayısının rakamlarını ters sırada yazarak elde edilen \(54321\) sayısını bir while döngüsüyle bulunuz.
Çözüm
Her adımda n’nin son rakamını alır ve ters sayısının sağına ekleriz: ters = 10 * ters + son_rakam. ters sırayla \(5\), \(54\), \(543\), \(5432\), \(54321\) olur.
n = 12345
ters = 0
while n > 0:
ters = 10 * ters + n % 10
n //= 10
print(ters)54321
\(\blacksquare\)
Alıştırma 8.5 (Sayı Üçgeni) İç içe iki döngüyle aşağıdaki deseni yazdırınız:
1
1 2
1 2 3
1 2 3 4
Çözüm
\(i\). satırda (\(i = 1, 2, 3, 4\)) \(1\)’den \(i\)’ye kadar sayılar yazılır. Dıştaki döngü satır numarasını, içteki döngü o satırdaki sayıları dolaşır; içteki döngünün bitişi dıştaki döngünün değişkenine bağlıdır.
for i in range(1, 5):
for j in range(1, i + 1):
print(j, end=" ")
print()1
1 2
1 2 3
1 2 3 4
\(\blacksquare\)
Alıştırma 8.6 (while ile Asallık Denemesi) Aşağıdaki program ne yapar? Çıktısını bulunuz.
for sayi in range(2, 21):
bolen = 2
asal = True
while bolen < sayi:
if sayi % bolen == 0:
asal = False
break
bolen += 1
if asal:
print(sayi, end=" ")
print()Çözüm
Dıştaki for \(2\)’den \(20\)’ye kadar sayıları dolaşır. Her sayı için içteki while, \(2\)’den sayının bir eksiğine kadar bölen adaylarını dener; bir bölen bulunursa asal False yapılır ve break yalnız içteki while’dan çıkar. Hiç bölen bulunmazsa sayı asaldır ve yazılır. Program \(20\)’ye kadar asal sayıları yazar: \(2, 3, 5, 7, 11, 13, 17, 19\).
for sayi in range(2, 21):
bolen = 2
asal = True
while bolen < sayi:
if sayi % bolen == 0:
asal = False
break
bolen += 1
if asal:
print(sayi, end=" ")
print()2 3 5 7 11 13 17 19
sayi = 2 için 2 < 2 yanlış olduğundan while hiç çalışmaz ve \(2\) asal kalır. \(\blacksquare\)
Alıştırma 8.7 (match-case ile Harf Notundan Puana) Kullanıcının girdiği harf notunu (A, B, C, D, F) \(4\)’lük sistemdeki puanına çeviren bir program yazınız: A \(4\), B \(3\), C \(2\), D \(1\), F \(0\). Küçük harf de kabul edilsin.
Çözüm
Girdiyi upper() ile büyük harfe çevirir, match-case ile beş seçeneği ve geçersiz girdiyi ayırırız. Kullanıcı b girsin:
harf = input("Harf notu: ").upper()
match harf:
case "A":
puan = 4
case "B":
puan = 3
case "C":
puan = 2
case "D":
puan = 1
case "F":
puan = 0
case _:
puan = None
if puan is None:
print("Geçersiz harf notu.")
else:
print(f"{harf} notunun puanı: {puan}")Harf notu: b
B notunun puanı: 3
puan is None ifadesi, puan’ın “değer yok” anlamındaki None olup olmadığını sorar; None ile karşılaştırmada == yerine is kullanılması bir alışkanlıktır. \(\blacksquare\)
Döngü araçlarımız artık tamamlandı: for ile koleksiyonları, iç içe döngülerle tabloları, while ile sayısı belli olmayan tekrarları yönetebiliyoruz. Bir sonraki bölüm Demetler, Koleksiyonlar ve Listeler bölümünde kısaca tanıdığımız değiştirilemez koleksiyonu ayrıntılı olarak ele alıyor.