Himpunan adalah kumpulan objek yang tidak berulang — operasi union, intersection, difference, dan complement muncul di set(), database JOIN, deduplicate data, dan permission role sets. Di episode ini kalian memahami sets secara formal dan menerapkannya dalam Python dan SQL.

Setelah di episode 6 kita memahami quantifier (∀, ∃) dan bagaimana mereka bekerja dengan koleksi data, pada episode ini kita mempelajari himpunan (sets) — struktur data yang mewakili kumpulan objek tanpa duplikat. Himpunan adalah konsep sentral dalam discrete mathematics dan muncul di mana-mana dalam programming: set() di Python, deduplicate data, database JOIN operations, dan permission role sets.
Mengapa himpunan penting? Karena dalam dunia nyata, kita sering perlu menjawab pertanyaan tentang kumpulan data: "siapa yang punya role A atau B?" (union), "siapa yang punya kedua role?" (intersection), "siapa yang punya A tapi tidak B?" (difference). Operasi ini secara langsung diterjemahkan ke kode dan SQL.
Himpunan A adalah kumpulan objek yang disebut anggota (elements). Tidak ada anggota yang duplikat, dan urutan tidak berpengaruh.
# Membuat set
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
# Duplikat dihilangkan otomatis
C = {1, 1, 2, 2, 3}
print(f"C = {C}") # {1, 2, 3}
# Membership test — O(1) average
print(f"3 ∈ A? {3 in A}") # True
print(f"9 ∈ A? {9 in A}") # False
print(f"9 ∉ A? {9 not in A}") # TrueUnion menggabungkan semua anggota dari kedua himpunan:
A = {"alice", "bob", "charlie"}
B = {"bob", "diana", "eve"}
# Union: semua yang ada di A atau B (atau keduanya)
union = A | B
# Atau: A.union(B)
print(f"A ∪ B = {union}")
# {'alice', 'bob', 'charlie', 'diana', 'eve'}
# Contoh: semua user yang punya role A atau B
admin_users = {"alice", "bob"}
editor_users = {"bob", "charlie"}
all_privileged = admin_users | editor_users
print(f"Privileged: {all_privileged}")Intersection hanya mengambil anggota yang ada di kedua himpunan:
A = {"alice", "bob", "charlie"}
B = {"bob", "diana", "eve"}
# Intersection: hanya yang ada di A DAN B
intersection = A & B
# Atau: A.intersection(B)
print(f"A ∩ B = {intersection}") # {'bob'}
# Contoh: user yang punya kedua role
admin_users = {"alice", "bob", "charlie"}
editor_users = {"bob", "charlie", "diana"}
fullstack = admin_users & editor_users
print(f"Fullstack: {fullstack}") # {'bob', 'charlie'}Difference mengambil anggota yang ada di A tetapi tidak di B:
A = {"alice", "bob", "charlie"}
B = {"bob", "diana", "eve"}
# Difference: ada di A tapi tidak di B
diff = A - B
# Atau: A.difference(B)
print(f"A \\ B = {diff}") # {'alice', 'charlie'}
# Contoh: user yang hanya admin, bukan editor
admin_only = admin_users - editor_users
print(f"Admin only: {admin_only}") # {'alice'}A = {"alice", "bob", "charlie"}
B = {"bob", "diana", "eve"}
# Symmetric difference: ada di A atau B, tapi tidak keduanya
sym_diff = A ^ B
# Atau: A.symmetric_difference(B)
print(f"A △ B = {sym_diff}")
# {'alice', 'charlie', 'diana', 'eve'}Complement adalah semua elemen di universal set yang tidak ada di A. Dalam programming, kita mendefinisikan universal set secara eksplisit:
semua_role = {"admin", "editor", "user", "guest"}
role_saya = {"admin", "editor"}
# Complement: role yang tidak saya punya
bukan_role_saya = semua_role - role_saya
print(f"Role lain: {bukan_role_saya}") # {'user', 'guest'}A ⊆ B artinya semua anggota A ada di B:
A = {1, 2}
B = {1, 2, 3, 4}
C = {1, 2}
# Subset
print(f"A ⊆ B? {A <= B}") # True — semua anggota A ada di B
print(f"B ⊆ A? {B <= A}") # False
# Proper subset (A ⊂ B, A ≠ B)
print(f"A ⊂ B? {A < B}") # True — A ⊆ B dan A ≠ B
print(f"A ⊆ C? {A <= C}") # True
print(f"A ⊂ C? {A < C}") # False — A = C, bukan proper subsetVenn diagram memvisualisasikan operasi himpunan:
A ∪ B A ∩ B A \ B A △ B
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│████████│ │ ┌─┐ │ │████ │ │████ ██│
│████████│ │ │█│ │ │████ │ │████ ██│
│████████│ │ └─┘ │ │████ │ │████ ██│
└────────┘ └────────┘ └────────┘ └────────┘Operasi JOIN di SQL secara langsung merepresentasikan operasi himpunan:
# Simulasi tabel
users = [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
{"id": 3, "name": "Charlie"},
{"id": 4, "name": "Diana"},
]
orders = [
{"user_id": 1, "item": "Laptop"},
{"user_id": 2, "item": "Mouse"},
{"user_id": 2, "item": "Keyboard"},
{"user_id": 5, "item": "Monitor"}, # user_id 5 tidak ada di users!
]
user_ids = {u["id"] for u in users}
order_user_ids = {o["user_id"] for o in orders}
# INNER JOIN: user yang punya order
inner = user_ids & order_user_ids
print(f"INNER: {inner}") # {1, 2}
# LEFT JOIN (users tanpa order)
left_only = user_ids - order_user_ids
print(f"LEFT (no order): {left_only}") # {3, 4}
# Orders tanpa user valid (referensi rusak)
orphan = order_user_ids - user_ids
print(f"Orphan orders: {orphan}") # {5}# Daftar email duplikat
emails = [
"alice@test.com",
"bob@test.com",
"alice@test.com",
"charlie@test.com",
"bob@test.com",
]
# Deduplicate
unique_emails = set(emails)
print(f"Asli: {len(emails)} email")
print(f"Unik: {len(unique_emails)} email")
print(f"Hilang: {len(emails) - len(unique_emails)} duplikat")
# Pertahankan urutan
seen = set()
unique_ordered = []
for email in emails:
if email not in seen:
seen.add(email)
unique_ordered.append(email)
print(f"Urutan unik: {unique_ordered}")roles_user = {"editor", "viewer"}
roles_required = {"admin", "editor"}
# Cek apakah user punya semua role yang dibutuhkan
has_all = roles_required <= roles_user
print(f"Has all required? {has_all}") # False — tidak punya admin
# Cek apakah user punya setidaknya satu role
has_any = bool(roles_required & roles_user)
print(f"Has any required? {has_any}") # True — punya editor
# Tambah role
roles_user.add("admin")
has_all_baru = roles_required <= roles_user
print(f"After adding admin: {has_all_baru}") # TrueNote
Operasi himpunan di Python (|, &, -, ^, <=, <) memiliki kompleksitas rata-rata O(min(len(A), len(B))) — jauh lebih cepat dari iterasi manual. Gunakan set untuk deduplicate dan bandingkan koleksi besar.
Inti yang harus dibawa pulang:
|, &, -, ^) untuk operasi himpunan — lebih cepat dan lebih jelas dari iterasi manual.Di episode 8 selanjutnya kita akan mempelajari relasi dan fungsi — domain, range, refleksif, simetris, transitif, dan fungsi injective, surjective, bijective. Himpunan yang baru kalian kuasai adalah domain dan range dari relasi ini!