← Kursa Dön
📄 Text · 12 min

Set (Küme) İşlemleri

Set, matematikteki küme kavramının Python'daki karşılığı. İki temel özelliği var: her eleman benzersiz (duplicate yok) ve sırasız (insertion order garanti değil). Bu iki özellik onu bazı problemlerde liste ve dictionary'den çok daha uygun yapar.

Bir parmak izi veritabanı düşün: Her parmak izi benzersiz, iki kişide aynı iz olamaz. Ve parmak izlerinin sırası önemli değil — önemli olan "bu iz veritabanında var mı?" sorusuna anında cevap vermek. İşte set tam olarak bu: benzersiz elemanlar topluluğu, O(1) üyelik testi (arama) ile. Listede arama O(n) iken set'te O(1) — bu fark milyonlarca elemanda devasa bir performans farkı yaratır.


Set Oluşturma

# Süslü parantezle
meyveler = {"elma", "armut", "muz", "çilek"}
print(meyveler)  # Sıra değişebilir!

# Duplicate'lar otomatik temizlenir
sayilar = {1, 2, 3, 2, 1, 4, 3, 5}
print(sayilar)  # {1, 2, 3, 4, 5}

# set() constructor ile
harfler = set("mississippi")
print(harfler)  # {'m', 'i', 's', 'p'}

# Listeden set
liste = [1, 2, 3, 2, 1]
kume = set(liste)
print(kume)  # {1, 2, 3}

# Range'den set
s = set(range(5))
print(s)  # {0, 1, 2, 3, 4}

⚠️ Boş Set Tuzağı

Bu Python'ın en bilinen gotcha'larından biri:

# ❌ Bu boş set DEĞİL — boş dictionary!
bos = {}
print(type(bos))  # <class 'dict'>

# ✅ Boş set oluşturmanın TEK yolu
bos_set = set()
print(type(bos_set))  # <class 'set'>

{} boş dict oluşturur, boş set değil! Boş set için her zaman set() kullan. Bu tasarım kararı tarihsel — dict Python'a set'ten önce eklendi ve {} söz dizimini aldı.

Set'e Neler Girebilir?

Set elemanları hashable olmalıdır (dict key'leri gibi):

# ✅ Hashable tipler — set'e girebilir
s = {42, 3.14, "merhaba", (1, 2), True, None, frozenset({1, 2})}

# ❌ Mutable tipler — set'e giremez
# s = {[1, 2]}           # TypeError: unhashable type: 'list'
# s = {{"a": 1}}         # TypeError: unhashable type: 'dict'
# s = {{1, 2}}           # TypeError: unhashable type: 'set'

💡 İpucu: "Hashable" = "değiştirilemez (immutable)" olarak düşünebilirsin. int, str, float, tuple, frozenset hashable; list, dict, set hashable değil. Bu kural hem set elemanları hem dict key'leri için geçerli.


Set Operasyonları: Küme Matematiği

Set'in gerçek gücü matematiksel küme operasyonlarında. Her operasyonun hem operatör hem metod versiyonu var:

Union (Birleşim): | veya union()

İki kümenin tüm elemanlarını birleştirir (duplicate olmadan):

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# İki yol — aynı sonuç
print(a | b)          # {1, 2, 3, 4, 5, 6}
print(a.union(b))     # {1, 2, 3, 4, 5, 6}

# Birden fazla set birleştirme
c = {7, 8}
print(a | b | c)      # {1, 2, 3, 4, 5, 6, 7, 8}
print(a.union(b, c))  # Aynı sonuç

Intersection (Kesişim): & veya intersection()

İki kümede de bulunan ortak elemanlar:

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a & b)                # {3, 4}
print(a.intersection(b))    # {3, 4}

Difference (Fark): - veya difference()

Birinci kümede olup ikincide olmayan elemanlar:

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a - b)              # {1, 2} — a'da olup b'de olmayan
print(b - a)              # {5, 6} — b'de olup a'da olmayan
print(a.difference(b))    # {1, 2}

Symmetric Difference (Simetrik Fark): ^ veya symmetric_difference()

Sadece birinde olan elemanlar (ortak olmayanlar):

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a ^ b)                        # {1, 2, 5, 6}
print(a.symmetric_difference(b))    # {1, 2, 5, 6}

# Simetrik fark = Birleşim - Kesişim
print((a | b) - (a & b))           # {1, 2, 5, 6} — aynı sonuç

Venn Diyagramı ile Görselleştirme

    a = {1, 2, 3, 4}        b = {3, 4, 5, 6}

         ┌───────────┐ ┌───────────┐
         │  1, 2     │ │     5, 6  │
         │     ┌─────┼─┼───┐      │
         │     │ 3,4 │ │   │      │
         │     └─────┼─┼───┘      │
         └───────────┘ └───────────┘

    a | b  = {1, 2, 3, 4, 5, 6}  (Tümü)
    a & b  = {3, 4}               (Ortak)
    a - b  = {1, 2}               (Sadece a)
    b - a  = {5, 6}               (Sadece b)
    a ^ b  = {1, 2, 5, 6}         (Ortaklar hariç)

Alt Küme ve Üst Küme Kontrolü

a = {1, 2, 3}
b = {1, 2, 3, 4, 5}

# a, b'nin alt kümesi mi?
print(a <= b)             # True
print(a.issubset(b))      # True

# b, a'nın üst kümesi mi?
print(b >= a)             # True
print(b.issuperset(a))    # True

# Gerçek alt küme (proper subset) — eşit olamaz
print(a < b)     # True  — a, b'nin gerçek alt kümesi
print(a < a)     # False — kendisinin gerçek alt kümesi değil
print(a <= a)    # True  — kendisinin alt kümesi (eşit dahil)

# Ortak eleman var mı kontrolü
x = {1, 2}
y = {3, 4}
print(x.isdisjoint(y))  # True — ortak eleman yok

Set Metodları

Eleman Ekleme ve Silme

s = {1, 2, 3}

# add: Tek eleman ekle
s.add(4)
print(s)  # {1, 2, 3, 4}
s.add(2)  # Zaten var — hiçbir şey olmaz
print(s)  # {1, 2, 3, 4}

# update: Birden fazla eleman ekle (iterable)
s.update([5, 6, 7])
print(s)  # {1, 2, 3, 4, 5, 6, 7}
s.update({8, 9}, [10])  # Birden fazla iterable
print(s)  # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

Eleman Silme — 3 Farklı Yol

s = {1, 2, 3, 4, 5}

# remove: Sil — yoksa KeyError!
s.remove(3)
print(s)  # {1, 2, 4, 5}
# s.remove(99)  # KeyError: 99

# discard: Sil — yoksa hiçbir şey olmaz (sessiz)
s.discard(99)  # Hata yok!
s.discard(4)
print(s)  # {1, 2, 5}

# pop: Rastgele bir eleman sil ve döndür
silinen = s.pop()
print(f"Silinen: {silinen}")
print(s)

# clear: Tümünü sil
s.clear()
print(s)  # set()

remove vs discard karşılaştırması:

remove()discard()
Eleman varsaSilerSiler
Eleman yoksaKeyError!Sessizce geçer
KullanımEleman olmalı diye düşünüyorsanOlup olmadığını bilmiyorsan

Yerinde (In-Place) Operasyonlar

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# |= : Union yerinde
a_kopya = a.copy()
a_kopya |= b
print(a_kopya)  # {1, 2, 3, 4, 5, 6}

# &= : Intersection yerinde
a_kopya = a.copy()
a_kopya &= b
print(a_kopya)  # {3, 4}

# -= : Difference yerinde
a_kopya = a.copy()
a_kopya -= b
print(a_kopya)  # {1, 2}

# ^= : Symmetric difference yerinde
a_kopya = a.copy()
a_kopya ^= b
print(a_kopya)  # {1, 2, 5, 6}

frozenset: Değişmez Set

frozenset, set'in immutable versiyonu. Tıpkı tuple'ın list'in immutable versiyonu olması gibi.

# Oluşturma
fs = frozenset([1, 2, 3, 4, 5])
print(fs)  # frozenset({1, 2, 3, 4, 5})

# Okuma operasyonları çalışır
print(3 in fs)        # True
print(len(fs))        # 5
print(fs & {3, 4, 5, 6})  # frozenset({3, 4, 5})

# Değiştirme operasyonları ÇALIŞMAZ
# fs.add(6)     # AttributeError
# fs.remove(1)  # AttributeError
# fs.pop()      # AttributeError

frozenset Neden Var?

# 1. Set içinde set — normal set hashable olmadığı için giremez
# ❌
# s = {{1, 2}, {3, 4}}  # TypeError: unhashable type: 'set'

# ✅ frozenset hashable!
s = {frozenset({1, 2}), frozenset({3, 4})}
print(s)

# 2. Dict key olarak
izinler = {
    frozenset({"read", "write"}): "editor",
    frozenset({"read"}): "viewer",
    frozenset({"read", "write", "admin"}): "admin",
}

kullanici_izin = frozenset({"read", "write"})
print(izinler[kullanici_izin])  # editor

# 3. Sabit set (değiştirilmemesi gereken)
DESTEKLENEN_DILLER = frozenset({"python", "java", "go", "rust"})

Pratik Kullanımlar

1. Duplicate Temizleme

En yaygın set kullanımı — listeden tekrar eden elemanları çıkarmak:

# Basit duplicate temizleme
liste = [1, 2, 3, 2, 1, 4, 3, 5, 4, 5]
benzersiz = list(set(liste))
print(benzersiz)  # [1, 2, 3, 4, 5] — sıra korunmayabilir!

# Sırayı koruyarak duplicate temizleme (Python 3.7+)
def sirali_benzersiz(iterable):
    gorulenler = set()
    sonuc = []
    for eleman in iterable:
        if eleman not in gorulenler:
            gorulenler.add(eleman)
            sonuc.append(eleman)
    return sonuc

liste = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
print(sirali_benzersiz(liste))  # [3, 1, 4, 5, 9, 2, 6]

# Python 3.7+ dict.fromkeys ile (daha kısa)
benzersiz = list(dict.fromkeys(liste))
print(benzersiz)  # [3, 1, 4, 5, 9, 2, 6]

2. Üyelik Testi (Membership Test)

# Büyük veri setinde arama
gecerli_kullanicilar = {"ahmet", "ayse", "mehmet", "fatma", "ali"}

girdi = input("Kullanıcı adı: ").lower()
if girdi in gecerli_kullanicilar:  # O(1) — anında!
    print("Geçerli kullanıcı")
else:
    print("Kullanıcı bulunamadı")

3. Ortak Elemanları Bulma

# İki kullanıcının ortak ilgi alanları
ahmet = {"python", "javascript", "müzik", "futbol", "film"}
ayse = {"java", "python", "resim", "müzik", "yüzme"}

ortak = ahmet & ayse
print(f"Ortak ilgi alanları: {ortak}")  # {'python', 'müzik'}

sadece_ahmet = ahmet - ayse
print(f"Sadece Ahmet: {sadece_ahmet}")

tum_ilgiler = ahmet | ayse
print(f"Toplam benzersiz ilgi alanı: {len(tum_ilgiler)}")

4. Veri Doğrulama

zorunlu_alanlar = {"isim", "email", "sifre"}
opsiyonel_alanlar = {"telefon", "adres", "dogum_tarihi"}
tum_gecerli_alanlar = zorunlu_alanlar | opsiyonel_alanlar

def form_dogrula(veri):
    gelen_alanlar = set(veri.keys())

    # Eksik zorunlu alanlar
    eksik = zorunlu_alanlar - gelen_alanlar
    if eksik:
        return f"Eksik alanlar: {eksik}"

    # Bilinmeyen alanlar
    bilinmeyen = gelen_alanlar - tum_gecerli_alanlar
    if bilinmeyen:
        return f"Geçersiz alanlar: {bilinmeyen}"

    return "Form geçerli ✅"

# Test
print(form_dogrula({"isim": "Ahmet", "email": "a@b.com", "sifre": "123"}))
print(form_dogrula({"isim": "Ahmet"}))
print(form_dogrula({"isim": "A", "email": "a@b", "sifre": "1", "xyz": "?"}))

5. Dosya Karşılaştırma

# İki dizindeki dosya farklarını bul
dizin1_dosyalar = {"a.py", "b.py", "c.py", "d.py"}
dizin2_dosyalar = {"b.py", "c.py", "e.py", "f.py"}

sadece_dizin1 = dizin1_dosyalar - dizin2_dosyalar
sadece_dizin2 = dizin2_dosyalar - dizin1_dosyalar
ortak = dizin1_dosyalar & dizin2_dosyalar

print(f"Sadece dizin1: {sadece_dizin1}")  # {'a.py', 'd.py'}
print(f"Sadece dizin2: {sadece_dizin2}")  # {'e.py', 'f.py'}
print(f"Her ikisinde:  {ortak}")          # {'b.py', 'c.py'}

Set vs List Performans: O(1) vs O(n)

Bu performans farkını somut rakamlarla görelim:

import time

# 10 milyon elemanlı veri yapıları
n = 10_000_000
buyuk_liste = list(range(n))
buyuk_set = set(range(n))

# Arama: Son elemanı bul
hedef = n - 1

# Liste araması — O(n)
baslangic = time.time()
hedef in buyuk_liste
liste_sure = time.time() - baslangic

# Set araması — O(1)
baslangic = time.time()
hedef in buyuk_set
set_sure = time.time() - baslangic

print(f"Liste araması: {liste_sure:.4f}s")  # ~0.05-0.1s
print(f"Set araması:   {set_sure:.6f}s")    # ~0.000001s
print(f"Set {liste_sure/set_sure:.0f}x daha hızlı!")

Zaman Karmaşıklığı Tablosu

İşlemListSet
x in s (arama)O(n)O(1)
Eleman eklemeO(1)*O(1)
Eleman silme (değere göre)O(n)O(1)
İterasyonO(n)O(n)

\* Liste sonuna append O(1), başına insert(0, x) O(n)

Ne Zaman Set, Ne Zaman Liste?

# ✅ Set kullan: Sık arama yapıyorsan
yasakli_kelimeler = {"spam", "reklam", "dolandırıcılık"}
if kelime in yasakli_kelimeler:  # O(1)
    filtrele()

# ✅ Liste kullan: Sıra önemliyse
gorevler = ["kahvaltı", "iş", "spor"]  # Sıralı olmalı

# ✅ Set kullan: Benzersizlik garantisi lazımsa
ziyaret_edilen_url = set()
ziyaret_edilen_url.add(url)  # Otomatik dedup

# ✅ Liste kullan: Duplicate'lara izin veriliyorsa
puanlar = [100, 85, 100, 72, 85]  # Aynı puan tekrar edebilir

⚠️ Dikkat: Set'in hız avantajı bellek maliyetiyle gelir. Set, hash tablosu kullandığı için listeden daha fazla bellek harcar. Küçük koleksiyonlarda (< 100 eleman) fark önemsiz. Büyük koleksiyonlarda ve sık arama yapılan yerlerde set tercih et.


Yaygın Hatalar ve Anti-Pattern'ler

1. Boş Set Oluşturma

# ❌ En yaygın hata!
bos = {}           # Bu dict, set değil!
print(type(bos))   # <class 'dict'>

# ✅ Doğru
bos = set()
print(type(bos))   # <class 'set'>

2. Unhashable Tip Ekleme

# ❌ Liste set'e eklenemez
s = set()
# s.add([1, 2])  # TypeError: unhashable type: 'list'

# ✅ Tuple'a çevir
s.add((1, 2))  # ✅ Tuple hashable

# ❌ Dict set'e eklenemez
# s.add({"a": 1})  # TypeError: unhashable type: 'dict'

# ✅ frozenset veya tuple kullan
s.add(frozenset({"a": 1}.items()))  # Çalışır ama pratik değil

3. Set'te Sıra Beklemek

# ❌ Set sırasız — her çalıştırmada farklı sıra olabilir!
s = {3, 1, 4, 1, 5, 9}
for eleman in s:
    print(eleman, end=" ")
# Çıktı: 1 3 4 5 9 (veya başka sırada!)

# ✅ Sıralı istiyorsan sorted() kullan
for eleman in sorted(s):
    print(eleman, end=" ")  # 1 3 4 5 9

4. Döngü İçinde Set Değiştirme

s = {1, 2, 3, 4, 5}

# ❌ RuntimeError: Set changed size during iteration
# for item in s:
#     if item % 2 == 0:
#         s.remove(item)

# ✅ Kopyası üzerinde dön
for item in s.copy():
    if item % 2 == 0:
        s.remove(item)
print(s)  # {1, 3, 5}

# ✅ Veya set comprehension ile yeni set
s = {1, 2, 3, 4, 5}
s = {item for item in s if item % 2 != 0}
print(s)  # {1, 3, 5}

5. Set ile Aritmetik Karıştırma

# Dikkat: - operatörü set'te fark, sayılarda çıkarma
a = {1, 2, 3}
b = {2, 3, 4}

sonuc = a - b
print(sonuc)  # {1} — küme farkı, çıkarma DEĞİL!

# & set'te kesişim, sayılarda bitwise AND
sonuc = a & b
print(sonuc)  # {2, 3} — kesişim

Set Comprehension

Liste ve dict comprehension gibi, set'ler için de tek satırda oluşturma:

# Temel set comprehension
kareler = {x**2 for x in range(10)}
print(kareler)  # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}

# Koşullu
cift_kareler = {x**2 for x in range(10) if x % 2 == 0}
print(cift_kareler)  # {0, 4, 16, 36, 64}

# String'den benzersiz kelimeler
metin = "python güzel python harika python en iyi dil"
benzersiz_kelimeler = {kelime.lower() for kelime in metin.split()}
print(benzersiz_kelimeler)

Gerçek Dünya Senaryoları

Tag/Etiket Sistemi

makale_taglari = {
    "makale_1": {"python", "programlama", "tutorial"},
    "makale_2": {"python", "veri-bilimi", "pandas"},
    "makale_3": {"javascript", "web", "react"},
    "makale_4": {"python", "web", "django"},
}

# Python ile ilgili makaleler
python_makaleleri = [
    makale for makale, taglar in makale_taglari.items()
    if "python" in taglar
]
print(f"Python makaleleri: {python_makaleleri}")

# Tüm benzersiz tag'ler
tum_taglar = set()
for taglar in makale_taglari.values():
    tum_taglar |= taglar
print(f"Toplam {len(tum_taglar)} benzersiz tag")

# En az 2 makalede geçen tag'ler
from collections import Counter
tag_sayilari = Counter(
    tag for taglar in makale_taglari.values() for tag in taglar
)
populer = {tag for tag, sayi in tag_sayilari.items() if sayi >= 2}
print(f"Popüler tag'ler: {populer}")

Anagram Kontrolü

def anagram_mi(kelime1, kelime2):
    """İki kelimenin anagram olup olmadığını kontrol et."""
    # Boşlukları kaldır, küçük harfe çevir
    k1 = kelime1.replace(" ", "").lower()
    k2 = kelime2.replace(" ", "").lower()

    # Harf setleri aynı mı? (Gerekli ama yeterli değil)
    if set(k1) != set(k2):
        return False

    # Harf sayıları da eşit mi?
    from collections import Counter
    return Counter(k1) == Counter(k2)

print(anagram_mi("listen", "silent"))    # True
print(anagram_mi("hello", "world"))      # False
print(anagram_mi("Astronomer", "Moon starer"))  # True

Grafik İlişki Takibi

# Arkadaşlık ilişkileri (çift yönlü)
arkadasliklar = {
    "Ahmet": {"Ayşe", "Mehmet", "Ali"},
    "Ayşe": {"Ahmet", "Fatma", "Ali"},
    "Mehmet": {"Ahmet", "Fatma"},
    "Ali": {"Ahmet", "Ayşe"},
    "Fatma": {"Ayşe", "Mehmet"},
}

# Ahmet ve Ayşe'nin ortak arkadaşları
ortak = arkadasliklar["Ahmet"] & arkadasliklar["Ayşe"]
print(f"Ortak arkadaşlar: {ortak}")  # {'Ali'}

# Ahmet'in tanımadığı kişiler
herkes = set(arkadasliklar.keys())
ahmet_bildiği = arkadasliklar["Ahmet"] | {"Ahmet"}
tanimadigi = herkes - ahmet_bildiği
print(f"Ahmet tanımıyor: {tanimadigi}")  # {'Fatma'}

Yetki Kontrolü

# Rol tabanlı erişim kontrolü
ROLLER = {
    "admin": {"read", "write", "delete", "manage_users"},
    "editor": {"read", "write"},
    "viewer": {"read"},
}

def erisim_kontrol(kullanici_rolu, gereken_izin):
    kullanici_izinleri = ROLLER.get(kullanici_rolu, set())
    return gereken_izin in kullanici_izinleri

def toplu_erisim_kontrol(kullanici_rolu, gereken_izinler):
    kullanici_izinleri = ROLLER.get(kullanici_rolu, set())
    return gereken_izinler.issubset(kullanici_izinleri)

# Test
print(erisim_kontrol("editor", "write"))      # True
print(erisim_kontrol("viewer", "delete"))      # False
print(toplu_erisim_kontrol("admin", {"read", "delete"}))  # True
print(toplu_erisim_kontrol("editor", {"read", "delete"})) # False

Özet

  • Set benzersiz elemanlar koleksiyonudur — duplicate otomatik temizlenir, sıra garanti değildir. Boş set set() ile oluşturulur, {} dict yapar!

  • Küme operasyonları: | birleşim, & kesişim, - fark, ^ simetrik fark. Hem operatör hem metod versiyonu var.

  • `remove()` vs `discard()`: remove olmayan elemanı silmeye çalışırsa KeyError verir, discard sessizce geçer.

  • frozenset set'in immutable versiyonu — dict key ve set elemanı olabilir, normal set olamaz.

  • Performans: Set'te arama O(1), listede O(n). Sık üyelik testi yapılan yerlerde set kullan — fark devasa.

  • Pratik kullanım: Duplicate temizleme, üyelik testi, veri doğrulama, dosya/koleksiyon karşılaştırma ve yetki kontrolü en yaygın senaryolar.