Python & AI Tutorials Logo
Pemrograman Python

17. Set: Bekerja dengan Data Unik yang Tidak Berurutan

Di bab-bab sebelumnya, kita sudah bekerja dengan list (koleksi yang berurutan dan mutable) dan dictionary (pemetaan key-value). Sekarang kita akan mengeksplorasi set, tipe koleksi Python yang dirancang khusus untuk menyimpan item unik dan melakukan operasi set matematis secara efisien.

Set sangat kuat ketika kamu perlu menghilangkan duplikasi, menguji keanggotaan dengan cepat, atau melakukan operasi seperti mencari elemen yang sama di antara koleksi. Berbeda dengan list, set tidak berurutan dan tidak bisa berisi nilai duplikat—mencoba menambahkan item yang sama dua kali tidak akan berdampak apa pun.

17.1) Membuat Set dan Operasi Dasar

17.1.1) Membuat Set dengan Kurung Kurawal

Cara paling umum untuk membuat set adalah menggunakan kurung kurawal {} dengan nilai yang dipisahkan koma:

python
# Membuat set bahasa pemrograman
languages = {"Python", "JavaScript", "Java", "C++"}
print(languages)  # Output: {'Python', 'JavaScript', 'Java', 'C++'}
print(type(languages))  # Output: <class 'set'>

Penting: Urutan elemen saat kamu mencetak set bisa berbeda dari urutan saat kamu memasukkannya. Set adalah koleksi yang tidak berurutan, artinya Python tidak mempertahankan urutan tertentu:

python
numbers = {5, 2, 8, 1, 9}
print(numbers)  # Output might be: {1, 2, 5, 8, 9} or another order

Urutan output bisa bervariasi antar eksekusi Python dan versi. Jangan pernah mengandalkan set untuk mempertahankan urutan tertentu—kalau urutan penting, gunakan list sebagai gantinya.

17.1.2) Set Menghapus Duplikasi Secara Otomatis

Salah satu properti set yang paling berguna adalah set otomatis menghilangkan nilai duplikat. Jika kamu mencoba membuat set dengan item duplikat, hanya satu salinan dari setiap nilai unik yang akan disimpan:

python
# Membuat set dengan nilai duplikat
student_ids = {101, 102, 103, 102, 101, 104}
print(student_ids)  # Output: {101, 102, 103, 104}
 
# Properti ini membuat set sempurna untuk menghapus duplikasi
grades = [85, 90, 85, 78, 90, 92, 78, 85]
unique_grades = set(grades)
print(unique_grades)  # Output: {78, 85, 90, 92}

Dedup otomatis ini terjadi karena set menggunakan model set matematis di mana setiap elemen hanya boleh muncul sekali. Ketika kamu menambahkan nilai yang sudah ada, set akan mengabaikan duplikat tersebut.

17.1.3) Membuat Set dengan Konstruktor set()

Kamu bisa membuat set dari iterable lain menggunakan konstruktor set(). Ini sangat berguna untuk mengonversi list, tuple, atau string menjadi set:

python
# Membuat set dari list
colors_list = ["red", "blue", "green", "red", "yellow"]
colors_set = set(colors_list)
print(colors_set)  # Output: {'red', 'blue', 'green', 'yellow'}
 
# Membuat set dari string (setiap karakter menjadi elemen)
letters = set("programming")
print(letters)  # Output: {'p', 'r', 'o', 'g', 'a', 'm', 'i', 'n'}
 
# Membuat set dari tuple
coordinates = set((10, 20, 30, 20, 10))
print(coordinates)  # Output: {10, 20, 30}

Saat kamu membuat set dari string, setiap karakter unik menjadi elemen terpisah. Ini berguna untuk mencari semua karakter yang berbeda di dalam teks:

python
text = "Mississippi"
unique_chars = set(text.lower())
print(unique_chars)  # Output: {'m', 'i', 's', 'p'}
print(f"The word contains {len(unique_chars)} unique letters")
# Output: The word contains 4 unique letters

17.1.4) Membuat Set Kosong

Ini jebakan penting: kamu tidak bisa membuat set kosong dengan {} karena Python menginterpretasikannya sebagai dictionary kosong. Sebagai gantinya, kamu harus menggunakan set():

python
# SALAH - Ini membuat dictionary kosong, bukan set
empty_dict = {}
print(type(empty_dict))  # Output: <class 'dict'>
 
# BENAR - Ini membuat set kosong
empty_set = set()
print(type(empty_set))  # Output: <class 'set'>
print(empty_set)  # Output: set()

Perbedaan ini ada karena dictionary ditambahkan ke Python sebelum set, jadi {} sudah dipakai untuk dictionary kosong. Saat kamu mencetak set kosong, Python menampilkannya sebagai set() untuk menghindari kebingungan.

Kebingungan umum pemula: Saat membuat set dengan satu elemen menggunakan variabel, set berisi nilai variabel, bukan nama variabel:

python
# Memahami pembuatan set dengan variabel
x = 5
my_set = {x}  # Membuat {5}, bukan {'x'}
print(my_set)  # Output: {5}
 
# Jika kamu ingin set yang berisi string 'x':
my_set = {'x'}
print(my_set)  # Output: {'x'}
 
# Ini berlaku untuk ekspresi apa pun
result = 10 + 5
my_set = {result}  # Membuat {15}
print(my_set)  # Output: {15}

17.1.5) Properti dan Operasi Dasar Set

Set mendukung beberapa operasi fundamental yang membuatnya berguna untuk pemrosesan data:

python
# Mengecek jumlah elemen unik
website_visitors = {"alice", "bob", "charlie", "alice", "david"}
print(f"Unique visitors: {len(website_visitors)}")
# Output: Unique visitors: 4
 
# Mengecek keanggotaan dengan 'in' (sangat cepat untuk set)
if "alice" in website_visitors:
    print("Alice visited the website")
# Output: Alice visited the website
 
# Mengecek bukan anggota
if "eve" not in website_visitors:
    print("Eve has not visited yet")
# Output: Eve has not visited yet

Pengujian keanggotaan dengan in adalah salah satu keunggulan utama set. Untuk koleksi besar, mengecek apakah sebuah item ada di set jauh lebih cepat dibanding mengecek di list. Kita akan mengeksplorasi mengapa ini penting di Bagian 17.5.

17.2) Menambahkan dan Menghapus Elemen dari Set

Berbeda dengan tuple (yang immutable), set bersifat mutable—kamu bisa menambahkan dan menghapus elemen setelah dibuat. Namun, elemen itu sendiri harus bertipe immutable (kita akan membahas pembatasan ini di Bagian 17.7).

17.2.1) Menambahkan Elemen Tunggal dengan add()

Menambahkan elemen individual ke set itu mudah dengan metode add(). Jika elemen sudah ada, set tetap tidak berubah—tidak ada error yang muncul, dan tidak ada duplikasi yang dibuat:

python
# Membangun set tugas yang sudah selesai
completed_tasks = {"task1", "task2"}
print(completed_tasks)  # Output: {'task1', 'task2'}
 
# Menambahkan tugas baru
completed_tasks.add("task3")
print(completed_tasks)  # Output: {'task1', 'task2', 'task3'}
 
# Menambahkan duplikat tidak berdampak apa pun
completed_tasks.add("task1")
print(completed_tasks)  # Output: {'task1', 'task2', 'task3'}

Perilaku ini membuat set ideal untuk melacak kemunculan unik. Kamu bisa memanggil add() dengan aman tanpa mengecek apakah elemen sudah ada—set menangani duplikasi secara otomatis.

17.2.2) Menambahkan Banyak Elemen dengan update()

Untuk menambahkan banyak elemen sekaligus, gunakan update() yang menerima iterable apa pun (list, tuple, set lain, dll.) dan menambahkan semua elemennya ke set:

python
# Memulai dengan set keterampilan yang kecil
skills = {"Python", "SQL"}
print(skills)  # Output: {'Python', 'SQL'}
 
# Menambahkan beberapa keterampilan dari list
new_skills = ["JavaScript", "Docker", "Python"]
skills.update(new_skills)
print(skills)  # Output: {'Python', 'SQL', 'JavaScript', 'Docker'}

Perhatikan bahwa "Python" muncul di set awal dan juga di list yang ditambahkan, tetapi set tetap hanya berisi satu salinan. Metode update() bisa menerima beberapa iterable sebagai argumen:

python
# Menggabungkan keterampilan dari beberapa sumber
current_skills = {"Python"}
course_skills = ["JavaScript", "HTML"]
job_requirements = {"SQL", "Python", "Docker"}
 
current_skills.update(course_skills, job_requirements)
print(current_skills)
# Output: {'Python', 'JavaScript', 'HTML', 'SQL', 'Docker'}

17.2.3) Menghapus Elemen dengan remove()

Menghapus elemen butuh kehati-hatian. Metode remove() menghapus elemen dari set, tetapi akan memunculkan KeyError jika elemen tidak ada:

python
# Mengelola pengguna aktif
active_users = {"alice", "bob", "charlie", "david"}
 
# Menghapus pengguna yang logout
active_users.remove("bob")
print(active_users)  # Output: {'alice', 'charlie', 'david'}
 
# Mencoba menghapus elemen yang tidak ada menyebabkan error
# active_users.remove("eve")  # Raises: KeyError: 'eve'

Karena remove() memunculkan error untuk elemen yang hilang, metode ini paling baik digunakan saat kamu yakin elemen ada, atau saat kamu ingin menangkap error jika tidak ada:

python
# Penghapusan aman dengan penanganan error (kita akan belajar lebih lanjut tentang try/except di Bab 28)
users = {"alice", "bob", "charlie"}
user_to_remove = "david"
 
if user_to_remove in users:
    users.remove(user_to_remove)
    print(f"Removed {user_to_remove}")
else:
    print(f"{user_to_remove} was not in the set")
# Output: david was not in the set

17.2.4) Menghapus Elemen dengan Aman menggunakan discard()

Untuk penghapusan elemen yang lebih aman tanpa memunculkan error, discard() menyediakan alternatif yang lebih “memaafkan”. Metode ini menghapus elemen jika ada, tetapi tidak melakukan apa pun jika elemen tidak ada:

python
# Mengelola keranjang belanja
cart_items = {"apple", "banana", "orange"}
 
# Menghapus item dengan aman (tidak error jika item tidak ada)
cart_items.discard("banana")
print(cart_items)  # Output: {'apple', 'orange'}
 
cart_items.discard("grape")  # No error, even though grape isn't in the set
print(cart_items)  # Output: {'apple', 'orange'}

Gunakan discard() saat kamu ingin memastikan elemen tidak ada di set, terlepas dari apakah awalnya ada atau tidak. Gunakan remove() saat ketiadaan elemen menunjukkan kondisi error yang ingin kamu tangkap.

17.2.5) Menghapus dan Mengembalikan Elemen Arbitrer dengan pop()

Metode pop() menghapus dan mengembalikan elemen arbitrer dari set. Karena set tidak berurutan, kamu tidak bisa memprediksi elemen mana yang akan dihapus:

python
# Memproses antrean tugas yang tertunda (urutan tidak penting)
pending_tasks = {"email", "report", "meeting", "review"}
 
# Proses satu tugas (kita tidak peduli yang mana)
task = pending_tasks.pop()
print(f"Processing: {task}")  # Output: Processing: email (or another task)
print(f"Remaining: {pending_tasks}")
# Output: Remaining: {'report', 'meeting', 'review'} (without the popped task)

Jika kamu memanggil pop() pada set kosong, itu akan memunculkan KeyError:

python
empty_set = set()
# empty_set.pop()  # Raises: KeyError: 'pop from an empty set'

Metode pop() berguna saat kamu perlu memproses semua elemen di set tetapi tidak peduli urutannya:

python
# Memproses semua item dalam set
items_to_process = {"item1", "item2", "item3"}
 
while items_to_process:
    item = items_to_process.pop()
    print(f"Processing {item}")
    # Proses item...
 
print("All items processed")
# Output:
# Processing item1
# Processing item2
# Processing item3
# All items processed

17.2.6) Menghapus Semua Elemen dengan clear()

Metode clear() menghapus semua elemen dari set, menyisakannya kosong:

python
# Mereset data sebuah sesi
session_data = {"user_id", "timestamp", "ip_address"}
print(session_data)  # Output: {'user_id', 'timestamp', 'ip_address'}
 
session_data.clear()
print(session_data)  # Output: set()
print(len(session_data))  # Output: 0

Ini lebih efisien dibanding membuat set kosong baru jika kamu ingin menggunakan ulang objek set yang sama.

Metode Modifikasi Set

Menambahkan Elemen

Menghapus Elemen

add element: Item tunggal

update iterable: Banyak item

remove element: Error jika tidak ada

discard element: Tidak error jika tidak ada

pop: Menghapus elemen arbitrer

clear: Menghapus semua elemen

Gunakan saat elemen harus ada

Gunakan saat tidak yakin ada

Gunakan saat urutan tidak penting

17.3) Operasi Set: Union, Intersection, Difference, dan Symmetric Difference

Set mendukung operasi set matematis yang memungkinkan kamu menggabungkan, membandingkan, dan menganalisis koleksi secara efisien. Operasi ini adalah hal fundamental dalam teori himpunan dan punya banyak aplikasi praktis dalam pemrosesan data.

17.3.1) Union: Menggabungkan Set

Mari mulai dengan skenario praktis untuk memahami mengapa union itu penting. Bayangkan kamu mengelola pendaftaran siswa di berbagai mata kuliah:

python
# Siswa yang terdaftar di mata kuliah berbeda
python_students = {"alice", "bob", "charlie"}
javascript_students = {"bob", "david", "eve"}
 
# Mencari semua siswa yang mengambil salah satu mata kuliah (atau keduanya)
all_students = python_students | javascript_students
print(all_students)
# Output: {'alice', 'bob', 'charlie', 'david', 'eve'}

Union dari dua set berisi semua elemen yang muncul di salah satu set (atau keduanya). Python menyediakan dua cara untuk menghitung union: operator | (ditunjukkan di atas) dan metode union():

python
# Hasil yang sama menggunakan metode union()
all_students = python_students.union(javascript_students)
print(all_students)
# Output: {'alice', 'bob', 'charlie', 'david', 'eve'}

Metode union() bisa menerima beberapa set sebagai argumen, sehingga memudahkan untuk menggabungkan data dari banyak sumber:

python
# Siswa di tiga mata kuliah berbeda
python_students = {"alice", "bob"}
javascript_students = {"bob", "charlie"}
sql_students = {"charlie", "david"}
 
# Semua siswa di semua mata kuliah
all_students = python_students.union(javascript_students, sql_students)
print(all_students)
# Output: {'alice', 'bob', 'charlie', 'david'}

Contoh lain union adalah menggabungkan daftar email dari departemen yang berbeda:

python
# Menggabungkan daftar email dari departemen yang berbeda
marketing_contacts = {"alice@company.com", "bob@company.com"}
sales_contacts = {"bob@company.com", "charlie@company.com"}
support_contacts = {"david@company.com", "alice@company.com"}
 
# Semua kontak unik dari seluruh departemen
all_contacts = marketing_contacts | sales_contacts | support_contacts
print(f"Total unique contacts: {len(all_contacts)}")
# Output: Total unique contacts: 4

17.3.2) Intersection: Mencari Elemen yang Sama

Memahami elemen mana yang muncul di beberapa set sangat penting untuk banyak tugas analisis data. Operasi intersection menjawab pertanyaan: "Apa kesamaan dari set-set ini?"

python
# Mencari pelanggan yang membeli kedua produk
customers_product_a = {101, 102, 103, 104, 105}
customers_product_b = {103, 104, 105, 106, 107}
 
# Pelanggan yang membeli kedua produk
both_products = customers_product_a & customers_product_b
print(f"Bought both: {both_products}")
# Output: Bought both: {103, 104, 105}

Intersection hanya berisi elemen yang muncul di kedua set. Kamu juga bisa menggunakan metode intersection(), yang menerima beberapa set:

python
# Mencari siswa yang terdaftar di ketiga mata kuliah
python_students = {"alice", "bob", "charlie"}
javascript_students = {"bob", "charlie", "david"}
sql_students = {"charlie", "eve", "bob"}
 
# Siswa yang mengambil ketiga mata kuliah
all_three = python_students.intersection(javascript_students, sql_students)
print(all_three)  # Output: {'bob', 'charlie'}

Berikut use case praktis untuk mencari produk yang tersedia di beberapa gudang:

python
# Mencari produk yang tersedia di beberapa gudang
warehouse_a = {"laptop", "mouse", "keyboard", "monitor"}
warehouse_b = {"mouse", "keyboard", "printer", "scanner"}
warehouse_c = {"keyboard", "monitor", "mouse", "desk"}
 
# Produk yang tersedia di semua gudang
available_everywhere = warehouse_a & warehouse_b & warehouse_c
print(f"Available in all locations: {available_everywhere}")
# Output: Available in all locations: {'mouse', 'keyboard'}

17.3.3) Difference: Mencari Elemen di Satu Set tetapi Tidak di Set Lain

Terkadang kamu perlu mengidentifikasi apa yang unik dari sebuah koleksi. Operasi difference mencari elemen yang ada di set pertama tetapi tidak ada di set kedua:

python
# Manajemen inventaris: mencari ketidaksesuaian
expected_items = {"item001", "item002", "item003", "item004"}
actual_items = {"item001", "item003", "item005"}
 
# Item yang hilang dari inventaris
missing = expected_items - actual_items
print(f"Missing items: {missing}")
# Output: Missing items: {'item002', 'item004'}
 
# Item yang tidak seharusnya ada di inventaris
unexpected = actual_items - expected_items
print(f"Unexpected items: {unexpected}")
# Output: Unexpected items: {'item005'}

Kamu juga bisa menggunakan metode difference():

python
# Siswa yang hanya ada di mata kuliah Python (tidak di JavaScript)
python_students = {"alice", "bob", "charlie"}
javascript_students = {"bob", "david", "eve"}
 
python_only = python_students.difference(javascript_students)
print(python_only)  # Output: {'alice', 'charlie'}

Penting: Operasi difference tidak komutatif—urutannya berpengaruh:

python
python_students = {"alice", "bob", "charlie"}
javascript_students = {"bob", "david", "eve"}
 
# Siswa di Python tetapi tidak di JavaScript
python_only = python_students - javascript_students
print(f"Python only: {python_only}")
# Output: Python only: {'alice', 'charlie'}
 
# Siswa di JavaScript tetapi tidak di Python
javascript_only = javascript_students - python_students
print(f"JavaScript only: {javascript_only}")
# Output: JavaScript only: {'david', 'eve'}

17.3.4) Symmetric Difference: Elemen di Salah Satu Set tetapi Tidak di Keduanya

Symmetric difference mencari elemen yang ada di salah satu set tetapi tidak di keduanya. Operasi ini sangat berguna untuk mengidentifikasi perubahan antara dua versi:

python
# Membandingkan dua versi konfigurasi
old_settings = {"debug", "logging", "cache", "compression"}
new_settings = {"logging", "cache", "monitoring", "security"}
 
# Pengaturan yang berubah (ditambah atau dihapus)
changes = old_settings ^ new_settings
print(f"Changed settings: {changes}")
# Output: Changed settings: {'debug', 'compression', 'monitoring', 'security'}
 
# Untuk melihat secara spesifik apa yang ditambahkan vs dihapus:
removed = old_settings - new_settings
added = new_settings - old_settings
print(f"Removed: {removed}")  # Output: Removed: {'debug', 'compression'}
print(f"Added: {added}")  # Output: Added: {'monitoring', 'security'}

Kamu juga bisa menggunakan metode symmetric_difference():

python
# Siswa yang ada tepat di satu mata kuliah (bukan di keduanya)
python_students = {"alice", "bob", "charlie"}
javascript_students = {"bob", "david", "eve"}
 
one_course_only = python_students.symmetric_difference(javascript_students)
print(one_course_only)
# Output: {'alice', 'charlie', 'david', 'eve'}

Berbeda dengan difference, symmetric difference komutatif—urutannya tidak berpengaruh:

python
result1 = python_students ^ javascript_students
result2 = javascript_students ^ python_students
print(result1 == result2)  # Output: True

Operasi Set

Union: A | B

Intersection: A & B

Difference: A - B

Symmetric Difference: A ^ B

Semua elemen di salah satu set

Hanya elemen yang ada di kedua set

Elemen di A tetapi tidak di B

Elemen di salah satu tetapi tidak di keduanya

17.4) Relasi Subset dan Superset (issubset, issuperset, isdisjoint)

Selain menggabungkan set, kita sering perlu memahami relasi di antara set-set tersebut. Python menyediakan metode untuk menguji apakah satu set berada di dalam set lain, mengandung set lain, atau tidak berbagi elemen sama sekali dengan set lain.

17.4.1) Menguji Subset dengan issubset() dan <=

Set A adalah subset dari set B jika setiap elemen di A juga ada di B. Dengan kata lain, B berisi semua elemen A (dan mungkin lebih).

python
# Prasyarat mata kuliah
basic_skills = {"reading", "writing"}
intermediate_skills = {"reading", "writing", "analysis"}
 
# Cek apakah basic_skills adalah subset dari intermediate_skills
print(basic_skills.issubset(intermediate_skills))  # Output: True
print(basic_skills <= intermediate_skills)  # Output: True (hasil sama)

Set selalu merupakan subset dari dirinya sendiri:

python
skills = {"Python", "SQL", "JavaScript"}
print(skills.issubset(skills))  # Output: True
print(skills <= skills)  # Output: True

Jika kamu ingin menguji proper subset (A adalah subset dari B tetapi tidak sama dengan B), gunakan operator <:

python
basic_skills = {"reading", "writing"}
intermediate_skills = {"reading", "writing", "analysis"}
 
# Proper subset: basic adalah subset dari intermediate DAN tidak sama
print(basic_skills < intermediate_skills)  # Output: True
 
# Bukan proper subset dari dirinya sendiri (karena sama)
print(basic_skills < basic_skills)  # Output: False

Contoh praktis pengujian subset adalah mengecek permission atau requirement:

python
# Sistem permission pengguna
required_permissions = {"read", "write"}
user_permissions = {"read", "write", "delete", "admin"}
 
# Cek apakah pengguna punya semua permission yang diperlukan
if required_permissions.issubset(user_permissions):
    print("Access granted")
else:
    print("Access denied - missing permissions")
# Output: Access granted
 
# Pengguna lain dengan permission yang tidak cukup
limited_user = {"read"}
if required_permissions.issubset(limited_user):
    print("Access granted")
else:
    missing = required_permissions - limited_user
    print(f"Access denied - missing: {missing}")
# Output: Access denied - missing: {'write'}

17.4.2) Menguji Superset dengan issuperset() dan >=

Set A adalah superset dari set B jika A berisi semua elemen B. Ini adalah relasi kebalikan dari subset—jika A adalah subset dari B, maka B adalah superset dari A.

python
# Level keterampilan
basic_skills = {"reading", "writing"}
advanced_skills = {"reading", "writing", "analysis", "research"}
 
# Cek apakah advanced_skills adalah superset dari basic_skills
print(advanced_skills.issuperset(basic_skills))  # Output: True
print(advanced_skills >= basic_skills)  # Output: True (hasil sama)

Seperti subset, set selalu merupakan superset dari dirinya sendiri:

python
skills = {"Python", "SQL"}
print(skills.issuperset(skills))  # Output: True

Untuk proper superset (A adalah superset dari B tetapi tidak sama dengan B), gunakan operator >:

python
basic_skills = {"reading", "writing"}
advanced_skills = {"reading", "writing", "analysis"}
 
# Proper superset: advanced berisi semua basic DAN punya lebih banyak
print(advanced_skills > basic_skills)  # Output: True
 
# Bukan proper superset dari dirinya sendiri
print(advanced_skills > advanced_skills)  # Output: False

17.4.3) Menguji Set Disjoint dengan isdisjoint()

Dua set disebut disjoint jika keduanya tidak memiliki elemen yang sama—intersection-nya kosong. Metode isdisjoint() mengembalikan True jika set-set tersebut tidak berbagi elemen:

python
# Mengecek konflik jadwal
morning_classes = {"math", "english", "history"}
afternoon_classes = {"science", "art", "music"}
 
# Cek apakah ada konflik (kelas yang sama di kedua sesi)
if morning_classes.isdisjoint(afternoon_classes):
    print("No scheduling conflicts")
else:
    conflicts = morning_classes & afternoon_classes
    print(f"Conflicts: {conflicts}")
# Output: No scheduling conflicts

Saat set tidak disjoint:

python
morning_classes = {"math", "english", "history"}
afternoon_classes = {"science", "math", "music"}
 
if morning_classes.isdisjoint(afternoon_classes):
    print("No scheduling conflicts")
else:
    conflicts = morning_classes & afternoon_classes
    print(f"Conflicts: {conflicts}")
# Output: Conflicts: {'math'}

Set kosong disjoint dengan semua set (termasuk set kosong lainnya):

python
empty = set()
numbers = {1, 2, 3}
 
print(empty.isdisjoint(numbers))  # Output: True
print(empty.isdisjoint(empty))  # Output: True

17.5) Kapan Menggunakan Set dibanding List

Memahami kapan harus menggunakan set versus list sangat penting untuk menulis kode Python yang efisien. Walaupun keduanya menyimpan koleksi item, keduanya punya karakteristik berbeda yang membuat masing-masing cocok untuk tugas yang berbeda.

17.5.1) Gunakan Set untuk Pengujian Keanggotaan yang Cepat

Salah satu keuntungan set yang paling signifikan adalah kecepatannya untuk pengujian keanggotaan. Mengecek apakah sebuah item ada di set jauh lebih cepat dibanding mengecek di list, terutama untuk koleksi besar:

python
# Mengecek apakah pengguna ada dalam koleksi besar
active_users_list = []
for i in range(10000):
    active_users_list.append("user" + str(i))
 
# Dengan list (lambat untuk koleksi besar)
print("user5000" in active_users_list)  # Mengecek tiap elemen sampai ketemu
 
active_users_set = set()
for i in range(10000):
    active_users_set.add("user" + str(i))
 
# Dengan set (cepat terlepas dari ukuran)
print("user5000" in active_users_set)  # Lookup langsung

Walau keduanya menghasilkan hasil yang sama, versi set jauh lebih cepat untuk koleksi besar. Ini karena set menggunakan hash table secara internal, memungkinkan lookup nyaris instan terlepas dari ukuran, sementara list harus mengecek tiap elemen secara berurutan.

17.5.2) Gunakan Set untuk Menghilangkan Duplikasi

Saat kamu perlu menghapus duplikasi dari sebuah koleksi, mengonversinya menjadi set adalah pendekatan yang paling sederhana:

python
# Menghapus entri duplikat dari input pengguna
survey_responses = [
    "yes", "no", "yes", "maybe", "yes", "no", "maybe", "yes"
]
 
# Ambil respons unik
unique_responses = set(survey_responses)
print(unique_responses)  # Output: {'yes', 'no', 'maybe'}
 
# Jika kamu butuh kembali dalam bentuk list (tanpa duplikasi)
unique_list = list(unique_responses)
print(unique_list)  # Output: ['yes', 'no', 'maybe'] (order may vary)

17.5.3) Gunakan Set untuk Operasi Set Matematis

Saat kamu perlu mencari elemen yang sama, perbedaan, atau union antara koleksi, set menyediakan operasi yang jelas dan efisien:

python
# Menganalisis pola pembelian pelanggan
customers_product_a = {101, 102, 103, 104, 105}
customers_product_b = {103, 104, 105, 106, 107}
 
# Pelanggan yang membeli kedua produk
both_products = customers_product_a & customers_product_b
print(f"Bought both: {both_products}")
# Output: Bought both: {103, 104, 105}
 
# Pelanggan yang hanya membeli produk A
only_a = customers_product_a - customers_product_b
print(f"Only product A: {only_a}")
# Output: Only product A: {101, 102}
 
# Semua pelanggan yang membeli setidaknya satu produk
all_customers = customers_product_a | customers_product_b
print(f"Total customers: {len(all_customers)}")
# Output: Total customers: 7

17.5.4) Gunakan List Saat Urutan Itu Penting

Set tidak berurutan, jadi jika urutan elemen penting, kamu harus menggunakan list:

python
# SALAH - Urutan tidak dipertahankan dengan set
task_order = {"wake up", "breakfast", "work", "lunch", "work", "dinner"}
print(task_order)  # Urutan tidak dapat diprediksi dan "work" hanya muncul sekali
 
# BENAR - Gunakan list saat urutan penting
task_order = ["wake up", "breakfast", "work", "lunch", "work", "dinner"]
print(task_order)
# Output: ['wake up', 'breakfast', 'work', 'lunch', 'work', 'dinner']

17.5.5) Gunakan List Saat Duplikasi Bermakna

Jika nilai duplikat membawa informasi (seperti frekuensi atau kemunculan ganda), gunakan list:

python
# Mencatat nilai kuis (duplikasi menunjukkan berapa siswa mendapat nilai tersebut)
quiz_scores = [85, 90, 85, 78, 90, 92, 85, 88]
 
# Dengan list, kita bisa menghitung kemunculan
score_85_count = quiz_scores.count(85)
print(f"Students who scored 85: {score_85_count}")
# Output: Students who scored 85: 3
 
# Dengan set, kita akan kehilangan informasi ini
unique_scores = set(quiz_scores)
print(unique_scores)  # Output: {78, 85, 88, 90, 92}
# Kita tidak bisa tahu berapa siswa mendapat setiap nilai

17.5.6) Gunakan List Saat Kamu Membutuhkan Indexing

Set tidak mendukung indexing karena tidak berurutan. Jika kamu perlu mengakses elemen berdasarkan posisi, gunakan list:

python
# SALAH - Set tidak mendukung indexing
colors = {"red", "blue", "green"}
# first_color = colors[0]  # Raises: TypeError: 'set' object is not subscriptable
 
# BENAR - Gunakan list untuk akses dengan indeks
colors = ["red", "blue", "green"]
first_color = colors[0]
print(first_color)  # Output: red

Keunggulan Set

Pengujian keanggotaan cepat

Dedup otomatis

Operasi set

Keunggulan List

Mempertahankan urutan

Mengizinkan duplikasi

Mendukung indexing

17.6) Frozenset dan Set Immutable

Sejauh ini, kita sudah bekerja dengan set biasa, yang mutable—kamu bisa menambah dan menghapus elemen setelah dibuat. Python juga menyediakan frozenset, yaitu versi set yang immutable. Setelah dibuat, frozenset tidak bisa dimodifikasi.

17.6.1) Membuat Frozenset

Kamu membuat frozenset menggunakan konstruktor frozenset(), mirip dengan cara membuat set biasa dengan set():

python
# Membuat frozenset dari list
colors = frozenset(["red", "blue", "green"])
print(colors)  # Output: frozenset({'red', 'blue', 'green'})
print(type(colors))  # Output: <class 'frozenset'>
 
# Membuat frozenset dari tuple
numbers = frozenset((1, 2, 3, 4, 5))
print(numbers)  # Output: frozenset({1, 2, 3, 4, 5})
 
# Membuat frozenset kosong
empty = frozenset()
print(empty)  # Output: frozenset()

Seperti set biasa, frozenset otomatis menghilangkan duplikasi:

python
# Duplikasi dihapus
values = frozenset([1, 2, 2, 3, 3, 3, 4])
print(values)  # Output: frozenset({1, 2, 3, 4})

17.6.2) Frozenset Bersifat Immutable

Setelah dibuat, kamu tidak bisa memodifikasi frozenset. Metode seperti add(), remove(), discard(), pop(), dan clear() tidak ada pada frozenset:

python
# Membuat frozenset
languages = frozenset(["Python", "JavaScript", "Java"])
 
# Mencoba memodifikasi akan memunculkan error
# languages.add("C++")  # AttributeError: 'frozenset' object has no attribute 'add'
# languages.remove("Java")  # AttributeError: 'frozenset' object has no attribute 'remove'

Immutability ini adalah karakteristik utama frozenset. Jika kamu perlu "memodifikasi" frozenset, kamu harus membuat yang baru:

python
# Frozenset asli
original = frozenset([1, 2, 3])
 
# Membuat frozenset baru dengan elemen tambahan
modified = frozenset(list(original) + [4])
print(original)  # Output: frozenset({1, 2, 3})
print(modified)  # Output: frozenset({1, 2, 3, 4})

17.6.3) Operasi Set Bekerja dengan Frozenset

Frozenset mendukung semua operasi set yang sama seperti set biasa (union, intersection, difference, dll.):

python
# Operasi set dengan frozenset
set_a = frozenset([1, 2, 3, 4])
set_b = frozenset([3, 4, 5, 6])
 
# Union
print(set_a | set_b)  # Output: frozenset({1, 2, 3, 4, 5, 6})
 
# Intersection
print(set_a & set_b)  # Output: frozenset({3, 4})
 
# Difference
print(set_a - set_b)  # Output: frozenset({1, 2})
 
# Symmetric difference
print(set_a ^ set_b)  # Output: frozenset({1, 2, 5, 6})

Kamu juga bisa mencampur set biasa dan frozenset dalam operasi:

python
regular_set = {1, 2, 3}
frozen_set = frozenset([3, 4, 5])
 
# Operasi antara set biasa dan frozenset
result = regular_set | frozen_set
print(result)  # Output: {1, 2, 3, 4, 5}
print(type(result))  # Output: <class 'set'> (result adalah set biasa)

17.6.4) Mengapa Menggunakan Frozenset?

Alasan utama menggunakan frozenset adalah karena frozenset bisa dipakai sebagai key dictionary atau sebagai elemen di set lain, yang tidak bisa dilakukan oleh set biasa:

python
# SALAH - Set biasa tidak bisa menjadi key dictionary
# regular_set = {1, 2, 3}
# my_dict = {regular_set: "value"}  # TypeError: unhashable type: 'set'
 
# BENAR - Frozenset bisa menjadi key dictionary
frozen_set = frozenset([1, 2, 3])
my_dict = {frozen_set: "value"}
print(my_dict)  # Output: {frozenset({1, 2, 3}): 'value'}
print(my_dict[frozen_set])  # Output: value

Contoh praktis menggunakan frozenset sebagai key dictionary:

python
# Menyimpan informasi tentang pasangan koordinat
# Setiap koordinat adalah frozenset dari nilai (x, y)
location_data = {
    frozenset([0, 0]): "origin",
    frozenset([1, 0]): "east",
    frozenset([1, 1]): "northeast"
}
 
# Mencari sebuah lokasi
point = frozenset([1, 0])
print(location_data[point])  # Output: east

Frozenset juga bisa menjadi elemen di set lain:

python
# SALAH - Set biasa tidak bisa menjadi elemen di dalam set
# set_of_sets = {{1, 2}, {3, 4}}  # TypeError: unhashable type: 'set'
 
# BENAR - Frozenset bisa menjadi elemen di dalam set
set_of_frozensets = {
    frozenset([1, 2]),
    frozenset([3, 4]),
    frozenset([5, 6])
}
print(set_of_frozensets)
# Output: {frozenset({1, 2}), frozenset({3, 4}), frozenset({5, 6})}

Contoh praktis merepresentasikan grup:

python
# Merepresentasikan tim di mana setiap tim adalah frozenset dari ID pemain
tournament_teams = {
    frozenset([101, 102, 103]),  # Tim A
    frozenset([201, 202, 203]),  # Tim B
    frozenset([301, 302, 303])   # Tim C
}
 
# Cek apakah tim tertentu terdaftar
team_to_check = frozenset([101, 102, 103])
if team_to_check in tournament_teams:
    print("Team is registered")
else:
    print("Team not found")
# Output: Team is registered

17.6.5) Mengonversi antara Set dan Frozenset

Kamu bisa dengan mudah mengonversi antara set biasa dan frozenset:

python
# Mengonversi set biasa menjadi frozenset
regular = {1, 2, 3, 4}
frozen = frozenset(regular)
print(frozen)  # Output: frozenset({1, 2, 3, 4})
 
# Mengonversi frozenset menjadi set biasa
frozen = frozenset([5, 6, 7, 8])
regular = set(frozen)
print(regular)  # Output: {5, 6, 7, 8}
 
# Sekarang kita bisa memodifikasi set biasa
regular.add(9)
print(regular)  # Output: {5, 6, 7, 8, 9}

Tipe Set

Set Biasa: Mutable

Frozenset: Immutable

Bisa menambah/menghapus elemen

Tidak bisa jadi key dict

Tidak bisa jadi elemen set

Tidak bisa dimodifikasi setelah dibuat

Bisa jadi key dict

Bisa jadi elemen set

17.7) Tipe Hashable dan Unhashable: Apa yang Bisa Menjadi Key Dictionary atau Elemen Set (dan Catatan Singkat tentang Hashing)

Sepanjang bab ini, kita sudah melihat bahwa set bisa berisi beberapa jenis objek, tetapi tidak yang lainnya. Misalnya, kamu bisa membuat set berisi integer atau string, tetapi tidak bisa membuat set berisi list. Pembatasan ini ada karena elemen set (dan key dictionary, seperti yang kita pelajari di Bab 16) harus bersifat hashable.

17.7.1) Apa Arti "Hashable"?

Objek hashable adalah objek yang punya nilai hash yang tidak pernah berubah selama masa hidupnya. Python menghitung nilai hash ini menggunakan fungsi bawaan bernama hash():

python
# Tipe hashable punya nilai hash
print(hash(42))  # Output: 42
print(hash("Python"))  # Output: (some large integer)
print(hash((1, 2, 3)))  # Output: (some large integer)

Nilai hash adalah integer yang digunakan Python secara internal untuk menemukan objek dengan cepat di set dan dictionary. Anggap saja ini seperti alamat atau indeks yang membantu Python menemukan sesuatu secara efisien.

Properti kunci: Agar sebuah objek hashable, nilai hash-nya harus tetap konstan sepanjang masa hidupnya. Ini berarti objek itu sendiri harus immutable—jika objek bisa berubah, nilai hash-nya juga perlu berubah, yang akan merusak set dan dictionary.

17.7.2) Tipe Immutable Bersifat Hashable

Semua tipe bawaan Python yang immutable bersifat hashable dan bisa digunakan sebagai elemen set atau key dictionary:

python
# Integer bersifat hashable
numbers = {1, 2, 3, 4, 5}
print(numbers)  # Output: {1, 2, 3, 4, 5}
 
# String bersifat hashable
words = {"apple", "banana", "cherry"}
print(words)  # Output: {'apple', 'banana', 'cherry'}
 
# Tuple bersifat hashable (jika hanya berisi elemen hashable)
coordinates = {(0, 0), (1, 1), (2, 2)}
print(coordinates)  # Output: {(0, 0), (1, 1), (2, 2)}
 
# Frozenset bersifat hashable
frozen_sets = {frozenset([1, 2]), frozenset([3, 4])}
print(frozen_sets)  # Output: {frozenset({1, 2}), frozenset({3, 4})}
 
# Boolean dan None bersifat hashable
mixed = {True, False, None, 42, "text"}
print(mixed)  # Output: {False, True, None, 42, 'text'}

17.7.3) Tipe Mutable Tidak Hashable

Tipe mutable seperti list, set biasa, dan dictionary tidak hashable karena isinya bisa berubah:

python
# List TIDAK hashable
# my_set = {[1, 2, 3]}  # TypeError: unhashable type: 'list'
 
# Set biasa TIDAK hashable
# set_of_sets = {{1, 2}, {3, 4}}  # TypeError: unhashable type: 'set'
 
# Dictionary TIDAK hashable
# my_set = {{"key": "value"}}  # TypeError: unhashable type: 'dict'

Mengapa mutability itu penting? Pertimbangkan apa yang akan terjadi jika kita bisa menambahkan list ke dalam set:

python
# Skenario hipotetis (ini sebenarnya tidak bekerja)
# my_list = [1, 2, 3]
# my_set = {my_list}  # Misalnya ini bekerja
# 
# # Python menghitung hash berdasarkan [1, 2, 3]
# # Sekarang kita memodifikasi list:
# my_list.append(4)  # Sekarang menjadi [1, 2, 3, 4]
# 
# # Nilai hash akan salah! Set akan menjadi rusak.

Inilah alasan Python mencegah objek mutable berada di dalam set atau digunakan sebagai key dictionary—itu akan merusak struktur data internal.

Kebingungan umum pemula: Walaupun set itu sendiri mutable (kamu bisa menambah dan menghapus elemen), elemen-elemennya harus immutable. Pemula kadang mencoba memodifikasi objek setelah menambahkannya ke set, tanpa menyadari perbedaan konsep ini:

python
# Kebingungan umum: set itu mutable, tetapi elemen harus immutable
# Set itu mutable - kamu bisa mengubah isinya
fruits = {'apple', 'banana'}
fruits.add('orange')     # ✓ Works
fruits.remove('apple')   # ✓ Works
 
# Tetapi elemen harus immutable - elemen tidak bisa diubah
my_list = [1, 2, 3]
# my_set = {my_list}  # ✗ TypeError: unhashable type: 'list'
# Mengapa? Jika kamu bisa memodifikasi my_list setelah menambahkannya, struktur internal set
# akan menjadi rusak.
 
# Ini bekerja karena tuple bersifat immutable
my_tuple = (1, 2, 3)
my_set = {my_tuple}  # ✓ Works - tuple tidak bisa dimodifikasi

17.7.4) Kasus Khusus Tuple

Tuple bersifat hashable hanya jika semua elemennya hashable. Tuple yang berisi objek mutable tidak hashable:

python
# Tuple dengan hanya elemen immutable - hashable
good_tuple = (1, 2, "three")
my_set = {good_tuple} # Works: good_tuple is hashable
print(my_set)  # Output: {(1, 2, 'three')}
 
# Tuple yang berisi list - TIDAK hashable
bad_tuple = (1, 2, [3, 4])
# my_set = {bad_tuple}  # TypeError: unhashable type: 'list'

Ini masuk akal: walaupun tuple itu sendiri immutable (kamu tidak bisa mengubah objek apa saja yang dikandungnya), jika salah satu objek itu mutable, maka "nilai" keseluruhan tuple bisa berubah:

python
# Menunjukkan mengapa tuple dengan elemen mutable tidak bisa di-hash
inner_list = [1, 2]
my_tuple = (inner_list, 3)
 
# Struktur tuple tetap, tetapi list di dalamnya bisa berubah
inner_list.append(3)  # Sekarang inner_list adalah [1, 2, 3]
# Tuple sekarang "berisi" data yang berbeda, tetapi itu masih objek tuple yang sama

17.7.5) Menguji Hashability

Kamu bisa menguji apakah sebuah objek hashable dengan mencoba menghitung hash-nya:

python
# Menguji hashability
def is_hashable(obj):
    """Mengecek apakah sebuah objek bersifat hashable."""
    try:
        hash(obj)
        return True
    except TypeError:
        return False
 
# Menguji berbagai tipe
print(is_hashable(42))  # Output: True
print(is_hashable("text"))  # Output: True
print(is_hashable((1, 2, 3)))  # Output: True
print(is_hashable([1, 2, 3]))  # Output: False
print(is_hashable({1, 2, 3}))  # Output: False
print(is_hashable({"key": "value"}))  # Output: False

17.7.6) Ringkasan Tipe Hashable

Hashable (bisa menjadi elemen set atau key dict):

  • Integer: 42
  • Float: 3.14
  • String: "text"
  • Tuple (jika semua elemen hashable): (1, 2, "three")
  • Frozenset: frozenset([1, 2, 3])
  • Boolean: True, False
  • None: None

Tidak Hashable (tidak bisa menjadi elemen set atau key dict):

  • List: [1, 2, 3]
  • Set biasa: {1, 2, 3}
  • Dictionary: {"key": "value"}
  • Tuple yang berisi elemen tidak hashable: (1, [2, 3])

Memahami hashability membantu kamu memilih struktur data yang tepat dan menghindari error umum saat bekerja dengan set dan dictionary. Prinsip kuncinya sederhana: kalau sebuah objek bisa berubah, objek itu tidak bisa di-hash; kalau tidak bisa di-hash, objek itu tidak bisa ada di set atau digunakan sebagai key dictionary.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai