ساختار داده مجموعه (Set) در پایتون
ساختار داده مجموعه (Set) در پایتون
ساختار داده مجموعه (Set) در پایتون
در پایتون، هنگامی که هدف ذخیره دادهها بدون ترتیب خاص و حذف خودکار مقادیر تکراری یا انجام عملیاتهای ریاضی مجموعهها (مانند اشتراک و اجتماع) باشد، از ساختار داده مجموعه (Set) استفاده میشود.
سِت (Set) چیست ؟
مجموعه یک ساختار داده نامرتب (Unordered)، تغییرپذیر (Mutable) و فاقد عضو تکراری (Unique Elements) است.
- یکتا بودن اعضا: هر عضو فقط یکبار میتواند در مجموعه حضور داشته باشد و دادههای تکراری بهصورت خودکار حذف میشوند.
- سرعت بالا: به دلیل پیادهسازی بر پایه جدول درهمسازی (Hash Table)، بررسی عضویت یک مقدار در آن است.
- کاربردها:
- حذف سریع دادههای تکراری از دنبالهها (Deduplication).
- بررسی سریع عضویت دادهها با سرعت بسیار بالا نسبت به لیست.
- انجام عملیات ریاضی مجموعهها (اجتماع، اشتراک، تفاضل و تفاضل متقارن).
- فیلتر کردن برچسبها و دستهبندیهای منحصربهفرد.
نحوه ساخت سِت
مجموعه با آکولاد {} یا با تابع سازنده set() ساخته میشود (برای ساخت مجموعه خالی حتماً باید از set() استفاده کرد، زیرا {} دیکشنری خالی میسازد):
# مجموعه خالی
empty_set = set()
# مجموعه با حذف خودکار تکراریها
unique_numbers = {1, 2, 2, 3, 4, 4, 5}
print(unique_numbers) # خروجی: {1, 2, 3, 4, 5}
اعضای یک مجموعه باید از انواع دادههای تغییرناپذیر و هشپذیر (Hashable) مانند عدد، رشته یا تاپل باشند (قرار دادن دادههای تغییرپذیر مثل لیست یا دیکشنری داخل سِت مجاز نیست):
mixed_set = {
101, # عدد صحیح
"Lead II", # رشته
True, # بولین
3.14, # اعشاری
(10, 20) # تاپل (تغییرناپذیر)
}
نحوه اندیسگذاری (Indexing) و برشدادن (Slicing)
- عدم وجود اندیسگذاری: مجموعهها ساختار نامرتب دارند؛ بنابراین اندیس عددی مانند
s[0]ندارند و تلاش برای استفاده از اندیس خطایTypeErrorتولید میکند. - عدم وجود اسلایسینگ: به دلیل نبود ترتیب و اندیس، برشدادن یا اسلایسینگ نیز در مجموعهها پشتیبانی نمیشود.
- روش پیمایش: دسترسی به اعضا تنها از طریق حلقه
forیا بررسی عضویت با عملگرinصورت میگیرد.
tags = {"ECG", "AI", "Signal"}
for item in tags:
print(item)
print("AI" in tags) # خروجی: True
متدهای پرکاربرد سِت همراه با حل مسئله
متد add(x)
- توضیح: یک عضو جدید به مجموعه اضافه میکند (اگر از قبل وجود داشته باشد تغییری ایجاد نمیشود).
- صورت مسئله: میخواهیم شناسه یک سنسور جدید را به لیست سنسورهای فعال اضافه کنیم.
active_sensors = {"sensor_1", "sensor_2"}
active_sensors.add("sensor_3")
print(active_sensors) # خروجی: {'sensor_1', 'sensor_2', 'sensor_3'}
متد remove(x)
- توضیح: عضو
xرا از مجموعه حذف میکند؛ اگر عضو وجود نداشته باشد خطایKeyErrorمیدهد. - صورت مسئله: میخواهیم یک پورت غیرفعالشده را از مجموعه پورتهای باز حذف کنیم.
open_ports = {80, 443, 8080}
open_ports.remove(8080)
print(open_ports) # خروجی: {80, 443}
متد discard(x)
- توضیح: عضو
xرا حذف میکند، اما در صورتی که عضو وجود نداشته باشد بدون ایجاد خطا کار را ادامه میدهد. - صورت مسئله: میخواهیم یک برچسب را بدون نگرانی از وجود یا عدم وجود آن از لیست تگها پاک کنیم.
labels = {"MI", "NORM", "STTC"}
labels.discard("HYP") # بدون ایجاد خطا اجرا میشود
print(labels) # خروجی: {'MI', 'NORM', 'STTC'}
متد pop()
- توضیح: یک عضو دلخواه (نامشخص) را از مجموعه برمیدارد و از آن حذف میکند.
- صورت مسئله: میخواهیم یک نمونه از بسته دادههای موجود را برای بررسی اولیه برداریم.
samples = {"sample_a", "sample_b", "sample_c"}
picked = samples.pop()
print("نمونه برداشتهشده:", picked)
print("مجموعه باقیمانده:", samples)
متد union(*others)
- توضیح: اجتماع دو یا چند مجموعه را به صورت یک مجموعه جدید بازمیگرداند.
- صورت مسئله: میخواهیم لیست کامل خطاهای ثبتشده در دو سرور را بدون تکرار تجمیع کنیم.
server1_errors = {"E01", "E02"}
server2_errors = {"E02", "E03"}
all_errors = server1_errors.union(server2_errors)
print(all_errors) # خروجی: {'E01', 'E02', 'E03'}
متد intersection(*others)
- توضیح: اشتراک دو یا چند مجموعه (اعضای مشترک) را بازمیگرداند.
- صورت مسئله: میخواهیم بیماران مشترکی که در هر دو بخش اورژانس و بستری ثبت شدهاند را بیابیم.
emergency_patients = {"P101", "P102", "P103"}
admitted_patients = {"P102", "P103", "P104"}
common = emergency_patients.intersection(admitted_patients)
print("بیماران مشترک:", common) # خروجی: {'P102', 'P103'}
متد difference(*others)
- توضیح: تفاضل مجموعهها (اعضایی که در مجموعه اول هستند ولی در مجموعه دوم نیستند) را برمیگرداند.
- صورت مسئله: میخواهیم وظایفی که هنوز انجام نشدهاند را با مقایسه کل کارها و کارهای انجامشده بیابیم.
all_tasks = {"task1", "task2", "task3", "task4"}
completed_tasks = {"task1", "task3"}
pending_tasks = all_tasks.difference(completed_tasks)
print("کارهای باقیمانده:", pending_tasks) # خروجی: {'task2', 'task4'}
متد symmetric_difference(other)
- توضیح: تفاضل متقارن (اعضایی که فقط در یکی از دو مجموعه قرار دارند و مشترک نیستند) را بازمیگرداند.
- صورت مسئله: میخواهیم ویژگیهایی که تنها در یکی از دو مدل فعال هستند را استخراج کنیم.
model1_features = {"CNN", "Attention", "Dropout"}
model2_features = {"CNN", "BiLSTM", "BatchNorm"}
diff_features = model1_features.symmetric_difference(model2_features)
print(diff_features) # خروجی: {'Attention', 'Dropout', 'BiLSTM', 'BatchNorm'}
متد issubset(other)
- توضیح: بررسی میکند که آیا تمام اعضای مجموعه فعلی درون مجموعه دیگر وجود دارد یا خیر (زیرمجموعه بودن).
- صورت مسئله: میخواهیم بررسی کنیم که آیا تمام مجوزهای مورد نیاز کاربر تایید شده است یا خیر.
required_perms = {"read", "write"}
user_perms = {"read", "write", "execute"}
print(required_perms.issubset(user_perms)) # خروجی: True
متد issuperset(other)
- توضیح: بررسی میکند که آیا مجموعه فعلی شامل تمام اعضای مجموعه دیگر هست یا خیر (ابرمجموعه بودن).
- صورت مسئله: میخواهیم بررسی کنیم که آیا سیستم فعلی تمام پیشنیازهای فنی را پوشش میدهد یا خیر.
installed_tools = {"python", "git", "docker", "vscode"}
required_tools = {"python", "git"}
print(installed_tools.issuperset(required_tools)) # خروجی: True
متد isdisjoint(other)
- توضیح: بررسی میکند که آیا دو مجموعه کاملاً از هم جدا هستند و هیچ عضو مشترکی ندارند یا خیر.
- صورت مسئله: میخواهیم اطمینان حاصل کنیم دو گروه آزمایشی هیچ بیمار مشترکی ندارند.
group_a = {"P1", "P2", "P3"}
group_b = {"P4", "P5", "P6"}
print("کاملاً مجزا هستند:", group_a.isdisjoint(group_b)) # خروجی: True
متد clear()
- توضیح: تمام اعضای موجود در مجموعه را پاک و آن را خالی میکند.
- صورت مسئله: میخواهیم مجموعه کش برچسبها را ریست کنیم.
cache = {"tag1", "tag2"}
cache.clear()
print(cache) # خروجی: set()
محدودیت مجموعهها
مجموعهها برای انجام عملیات ریاضی مستقیم و عددی مناسب نیستند:
- عملگرهای ریاضی برداری (مانند ضرب یا جمع در مقادیر ثابت) روی مجموعه تعریف نشدهاند و خطای
TypeErrorرخ میدهد. - به دلیل نداشتن ترتیب مشخص، دادههای عددی متوالی را نمیتوان بهصورت بردار ذخیره کرد.
set_a = {1, 2, 3}
# دستور زیر با خطای TypeError مواجه میشود:
# result = set_a * 2
نکته: برای محاسبات برداری، ماتریسی و دادههای پیوسته از کتابخانه NumPy استفاده میشود.
سه مثال کاربردی
مثال ۱: حذف دادههای تکراری از یک لیست
تبدیل لیست به سِت و بازگرداندن آن به لیست برای دریافت سریع مقادیر یکتا:
raw_predictions = ["MI", "NORM", "NORM", "STTC", "MI", "HYP"]
unique_classes = list(set(raw_predictions))
print("کلاسهای یکتا:", unique_classes)
# خروجی: ['NORM', 'STTC', 'HYP', 'MI'] (ترتیب نامشخص)
مثال ۲: بررسی سریع عضویت و فیلتر کلمات هرزنامه
سرعت بالای بررسی وجود یک کلمه در لیست سیاه (Fast Lookup) با استفاده از مجموعه:
blacklist = {"spam", "free", "winner", "bonus"}
input_message = "claim your free ticket now"
words = input_message.split()
has_spam = any(word in blacklist for word in words)
print("آیا پیام حاوی کلمات مشکوک است؟", has_spam) # خروجی: True
مثال ۳: یافتن مهارتهای مشترک بین دو فرد یا سیستم
استفاده از عملیات اشتراک برای سنجش انطباق نیازمندیها:
job_requirements = {"Python", "Machine Learning", "FastAPI", "Docker"}
applicant_skills = {"Python", "Docker", "SQL", "Git"}
matched_skills = job_requirements.intersection(applicant_skills)
missing_skills = job_requirements.difference(applicant_skills)
print("مهارتهای منطبق:", matched_skills) # خروجی: {'Python', 'Docker'}
print("مهارتهای ناموجود:", missing_skills) # خروجی: {'Machine Learning', 'FastAPI'}
