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() ile list.sort() arasındaki davranış farkını açıklayabilmeli,
  • artan ve azalan sıralama yapabilmeli,
  • key parametresiyle 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.

Warning

Ş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:

  1. önce department,
  2. 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,
  • key gibi 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 ve None döndürür.
  • key, kayıtların hangi değere göre karşılaştırılacağını belirler.
  • reverse=True sı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

  1. sorted(values) ile values.sort() arasındaki iki temel fark nedir?
  2. key parametresi ne işe yarar?
  3. (department, grade) anahtarı hangi sırayla karşılaştırılır?
  4. Kararlı sıralama neyi korur?
  5. Orijinal sırayı daha sonra kullanmanız gerekiyorsa hangi sıralama yaklaşımı daha güvenlidir?
Back to top