Python ile pratik sıralama
Önceki hafta sıralama algoritmasının nasıl çalıştığını görünür kılmak için insertion sort’u uyguladık. Gerçek Python programlarında ise çoğu zaman kendi sıralama algoritmamızı yazmayız; dilin güçlü ve iyi test edilmiş yerleşik araçlarını kullanırız.
Bu hafta sorted(), list.sort(), key, reverse ve çok ölçütlü sıralamayı öğreneceğiz. Ayrıca Python’ın sıralamasının kararlı (stable) olmasının neden yararlı olduğunu göreceğiz.
1 Bu hafta neleri yapabilmelisiniz?
Bölümün sonunda:
sorted()ilelist.sort()arasındaki davranış farkını açıklayabilmeli,- artan ve azalan sıralama yapabilmeli,
keyparametresiyle kayıtlara göre sıralama yapabilmeli,- lambda ifadelerini sınırlı ve okunabilir biçimde kullanabilmeli,
- çok ölçütlü sıralama gerçekleştirebilmeli,
- kararlı sıralamanın eşit anahtarlı kayıtlar için etkisini açıklayabilmeli,
- sıralama kararında veriyi değiştirme/kopyalama etkisini dikkate alabilmelisiniz.
2 sorted() yeni bir liste üretir
#| edit: false
#| completion: false
numbers = [8, 3, 10, 1, 5]
ordered = sorted(numbers)
print("Orijinal:", numbers)
print("Yeni liste:", ordered)
sorted() verilen veriyi doğrudan değiştirmez; sıralanmış yeni bir liste döndürür.
3 list.sort() mevcut listeyi değiştirir
#| edit: false
#| completion: false
numbers = [8, 3, 10, 1, 5]
result = numbers.sort()
print("Liste:", numbers)
print("sort() dönüş değeri:", result)
list.sort() listeyi yerinde (in-place) değiştirir ve None döndürür.
Şu kullanım hatalı bir beklenti yaratır:
ordered = numbers.sort()Burada ordered sıralı liste değil, None olur. Yeni bir liste istiyorsanız ordered = sorted(numbers) kullanın.
4 Azalan sıralama
#| edit: false
#| completion: false
numbers = [8, 3, 10, 1, 5]
print(sorted(numbers, reverse=True))
reverse=True, sıralama yönünü tersine çevirir.
5 String sıralaması
#| edit: false
#| completion: false
names = ["Zeynep", "Ali", "Ece", "Bora"]
print(sorted(names))
String sıralaması karakter karşılaştırmalarına göre yapılır. Büyük-küçük harf ve Türkçe karakter davranışı bağlama göre beklediğiniz doğal dil sırasıyla birebir aynı olmayabilir. Bu derste locale tabanlı sıralamayı ayrıntılı işlemeyeceğiz.
6 key: neye göre sıralıyoruz?
Kayıt listesinde sözlüğün kendisini doğrudan sıralamak yerine bir anahtar fonksiyonu belirtiriz:
#| edit: false
#| completion: false
students = [
{"name": "Ayşe", "grade": 82},
{"name": "Bora", "grade": 71},
{"name": "Cem", "grade": 94},
]
ordered = sorted(students, key=lambda student: student["grade"])
for student in ordered:
print(student["name"], student["grade"])
Buradaki lambda ifadesi şu soruya yanıt verir:
Her kayıt için karşılaştırmada hangi değeri kullanayım?
Bu örnekte cevap student["grade"] değeridir.
7 Lambda yerine normal fonksiyon
Lambda zorunlu değildir:
#| edit: false
#| completion: false
def grade_of(student):
return student["grade"]
students = [
{"name": "Ayşe", "grade": 82},
{"name": "Bora", "grade": 71},
{"name": "Cem", "grade": 94},
]
print(sorted(students, key=grade_of))
Kural karmaşıklaşırsa normal fonksiyon daha okunabilir olabilir. Lambda’yı kısa ve tek ifadeli anahtarlar için kullanacağız.
8 Nota göre azalan sıralama
#| edit: false
#| completion: false
students = [
{"name": "Ayşe", "grade": 82},
{"name": "Bora", "grade": 71},
{"name": "Cem", "grade": 94},
]
ordered = sorted(
students,
key=lambda student: student["grade"],
reverse=True,
)
print(ordered)
9 Alıştırma — ürünleri fiyata göre sırala
Ürünleri price alanına göre küçükten büyüğe sıralayıp ordered değişkenine atayın.
#| exercise: hafta10-price-sort
#| completion: false
#| persist: true
products = [
{"name": "Defter", "price": 45},
{"name": "Kalem", "price": 12},
{"name": "Çanta", "price": 350},
{"name": "Silgi", "price": 8},
]
ordered = [] # Bu satırı değiştirin.
print([product["name"] for product in ordered])
Beklenen sıra:
['Silgi', 'Kalem', 'Defter', 'Çanta']
#| exercise: hafta10-price-sort
#| check: true
scope = {}
try:
exec(user_code, scope)
ordered = scope.get("ordered")
correct = (
isinstance(ordered, list)
and [p["name"] for p in ordered] == ["Silgi", "Kalem", "Defter", "Çanta"]
)
except Exception:
correct = False
feedback = (
{"correct": True, "message": "Ürünler price alanına göre doğru sıralandı."}
if correct
else {"correct": False, "message": "sorted(products, key=lambda product: product['price']) kullanmayı deneyin."}
)
feedback
key fonksiyonu her ürün için price değerini döndürmelidir.
Solution.
ordered = sorted(products, key=lambda product: product["price"])10 Çok ölçütlü sıralama
Öğrencileri önce bölüme, aynı bölüm içinde nota göre sıralamak isteyelim. key bir tuple döndürebilir:
#| edit: false
#| completion: false
students = [
{"name": "Ayşe", "department": "Yazılım", "grade": 82},
{"name": "Bora", "department": "Siber", "grade": 91},
{"name": "Cem", "department": "Yazılım", "grade": 75},
{"name": "Deniz", "department": "Siber", "grade": 68},
]
ordered = sorted(
students,
key=lambda student: (student["department"], student["grade"]),
)
for student in ordered:
print(student)
Tuple karşılaştırması soldan sağa ilerler:
- önce
department, - eşitse
grade.
11 Bir ölçüt artan, diğeri azalan olsun
Sayısal değerlerde ters yön için negatif değer kullanılabilir:
#| edit: false
#| completion: false
students = [
{"name": "Ayşe", "department": "Yazılım", "grade": 82},
{"name": "Bora", "department": "Siber", "grade": 91},
{"name": "Cem", "department": "Yazılım", "grade": 75},
{"name": "Deniz", "department": "Siber", "grade": 68},
]
ordered = sorted(
students,
key=lambda student: (student["department"], -student["grade"]),
)
for student in ordered:
print(student["department"], student["grade"], student["name"])
Burada bölüm artan, not ise bölüm içinde azalan sıralanır.
12 Kararlı sıralama neden önemlidir?
Python’ın yerleşik sıralaması kararlıdır (stable). Eşit anahtar değerine sahip öğelerin önceki göreli sırası korunur.
#| edit: false
#| completion: false
records = [
{"name": "Ayşe", "grade": 80},
{"name": "Bora", "grade": 90},
{"name": "Cem", "grade": 80},
{"name": "Deniz", "grade": 90},
]
ordered = sorted(records, key=lambda record: record["grade"])
for record in ordered:
print(record)
80 alan Ayşe, başlangıçta Cem’den önceydi; sıralama anahtarları eşit olduğunda bu sıra korunur. Aynı durum 90 alan Bora ve Deniz için de geçerlidir.
Kararlılık, ardışık sıralamalarla çok ölçütlü düzen kurmaya da izin verir:
#| edit: false
#| completion: false
students = [
{"name": "Ayşe", "department": "Yazılım", "grade": 82},
{"name": "Bora", "department": "Siber", "grade": 91},
{"name": "Cem", "department": "Yazılım", "grade": 75},
{"name": "Deniz", "department": "Siber", "grade": 68},
]
# Önce ikincil ölçüt: not azalan
students = sorted(students, key=lambda s: s["grade"], reverse=True)
# Sonra birincil ölçüt: bölüm artan
students = sorted(students, key=lambda s: s["department"])
for student in students:
print(student)
Tek tuple anahtarı genellikle daha sade olsa da bu örnek kararlılığın etkisini görünür kılar.
13 operator.itemgetter
Sözlük veya tuple içinden doğrudan alan seçmek için standart kütüphanedeki itemgetter kullanılabilir:
#| edit: false
#| completion: false
from operator import itemgetter
products = [
{"name": "Defter", "price": 45},
{"name": "Kalem", "price": 12},
{"name": "Silgi", "price": 8},
]
print(sorted(products, key=itemgetter("price")))
Bu ders için lambda kullanımı yeterlidir; itemgetter yalnızca pratik bir alternatif olarak tanınmalıdır.
14 Orijinal veri değişsin mi?
Şu soruyu her zaman sorun:
Sıralama sonucunda mevcut listenin düzeni değişmeli mi?
- evet →
list.sort()düşünülebilir, - hayır / orijinal sıra lazım →
sorted()daha güvenlidir.
Aliasinge dikkat:
#| edit: false
#| completion: false
numbers = [3, 1, 2]
alias = numbers
numbers.sort()
print(numbers)
print(alias)
İki değişken aynı listeyi gösterdiği için değişiklik ikisinden de görünür.
15 Yerleşik sıralama neden tercih edilir?
Gerçek uygulamada sorted() ve .sort():
- iyi test edilmiştir,
- genel amaçlıdır,
keygibi güçlü özellikler sunar,- elle yazılan temel sıralamalardan çok daha iyi performans gösterebilir.
Önceki haftadaki insertion sort uygulamasının amacı, yerleşik araçların yerine geçmek değil; sıralama algoritması düşüncesini anlamaktır.
16 Kavram köşesi: öncelik kuyruğu ve heap
Bazı problemlerde tüm veriyi baştan sona sıralamak yerine sürekli olarak “en küçük” veya “en büyük” öncelikli öğeyi almak isteriz. Öncelik kuyruğu (priority queue) bu ihtiyaca yönelik bir soyut veri türüdür; heap ise bunu gerçekleştirmede yaygın bir veri yapısıdır.
Bu derste heap uygulaması veya heapq ayrıntıları zorunlu değildir. Hatırlanması gereken fikir:
Tam sıralama ile sürekli en öncelikli öğeyi seçme aynı problem değildir.
17 Bölüm özeti
sorted()yeni bir sıralı liste döndürür.list.sort()mevcut listeyi yerinde değiştirir veNonedöndürür.key, kayıtların hangi değere göre karşılaştırılacağını belirler.reverse=Truesıralama yönünü tersine çevirir.- Tuple anahtarlar çok ölçütlü sıralama sağlar.
- Python’ın sıralaması kararlıdır.
- Gerçek uygulamada yerleşik sıralama araçları, elle temel sıralama algoritması yazmaya tercih edilir.
18 Kendinizi kontrol edin
sorted(values)ilevalues.sort()arasındaki iki temel fark nedir?keyparametresi ne işe yarar?(department, grade)anahtarı hangi sırayla karşılaştırılır?- Kararlı sıralama neyi korur?
- Orijinal sırayı daha sonra kullanmanız gerekiyorsa hangi sıralama yaklaşımı daha güvenlidir?