مقدمه

مجموعه‌ها (sets) نوع دیگری از کالکشن‌های پایتون هستند که نوع set در پایتون برای کار با آنها در نظر گرفته شده است. یک مجموعه در پایتون، کالکشنی است تغییرپذیر و غیرترتیبی که شامل آیتم‌ها یا اعضای غیر تکراری است. علاوه بر set، یک کالکشن دیگر نیز برای کار با مجموعه‌ها در نظر گرفته شده که frozenset نام دارد و ورژن تغییرناپذیر set محسوب می‌شود.

ایجاد یک مجموعه

برای ایجاد یک مجموعه در پایتون، می‌توانیم از آکلادها یا تابع set() استفاده کنیم. ما برای ایجاد دیکشنری‌ها هم از آکلاد استفاده می‌کردیم اما در مورد دیکشنری، آیتم‌ها به صورت جفت‌های key: value درون آکلادها وارد می‌شوند ولی آیتم‌های مجموعه به صورت منفرد هستند.

Copy Icon python_sets.py
primes = {2, 3, 5, 7} 
print(primes)

evens = set([2, 4, 6, 8])
odds = set((1, 2, 5, 7)) 
print(evens)
print(odds)

در اینجا یک مجموعه شامل اعداد اول یک‌رقمی با استفاده از آکلادها و دو مجموعه شامل اعداد فرد و زوج یک‌رقمی با استفاده از تابع set() ایجاد شده است. توجه داشته باشید که تابع set() نمی‌تواند بیش از یک آرگومان دریافت کند. در مثال بالا، یک کالکشن از نوع لیست و یک کالکشن از نوع تاپل به این تابع داده شده است. نتیجه‌ی اجرای این کد، به صورت زیر خواهد بود.

{2, 3, 5, 7}
{8, 2, 4, 6}
{1, 3, 5, 7}
          

همانطور که در مقدمه هم اشاره شد، مجموعه‌ها شامل اعضای غیر تکراری هستند. یعنی اگر عضوی داشته باشیم که دو یا چند بار تکرار شده باشد، فقط یک عضو در نظر گرفته می‌شود. مثال زیر را ببینید.

Copy Icon python_sets.py
numbers = {1, 2, 3, 2, 3}
print(f"The length of numbers is {len(numbers)}")
            
for number in numbers: 
  print(number)

اگر این کد را اجرا کنیم، نتیجه‌ی زیر را مشاهده خواهیم کرد که نشان می‌دهد اعضای تکراری در مجموعه در نظر گرفته نمی‌شوند.

The length of numbers is 3
1
2
3
          

این ویژگیِ مجموعه‌ها، آنها را به یک انتخاب مناسب برای سناریوهای غیر تکراری تبدیل می‌کند. به عنوان مثال، فرض کنید یک دیکشنری از آیتم‌ها داریم که هر آیتم، نام دانشجو و زبان برنامه‌نویسی مورد علاقه‌ی او را نشان می‌دهد. اگر بخواهیم، مقادیر این دیکشنری (یعنی زبان‌های برنامه‌نویسی) را در خروجی چاپ کنیم، می‌توانیم این کار را به صورت زیر انجام دهیم.

Copy Icon python_sets.py
favorite_languages = {
  'john': 'python',
  'jane': 'c',
  'david': 'rust',
  'sarah': 'python',
  'peter': 'c',
  'michael': 'python'
  }
            
for language in favorite_languages.values(): 
  print(language.title())

اگر این کد را اجرا کنیم، خواهیم دید که مقادیر موجود در دیکشنری، بدون توجه به تکراری بودن یا نبودن در خروجی نمایش داده می‌شوند. برای مثال، عبارت python سه بار در خروجی دیده می‌شود. اما اگر بخواهیم فقط مقادیر یکتا و غیر تکراری در خروجی نمایش داده شوند، باید ترتیبی دهیم که پیمایش روی یک مجموعه انجام شود. برای این کار، کافیست کالکشن موجود در ساختار for را (که یک کالکشن از نوع dict_values است) به تابع set() پاس کنیم.

Copy Icon python_sets.py
favorite_languages = {
  'john': 'python',
  'jane': 'c',
  'david': 'rust',
  'sarah': 'python',
  'peter': 'c',
  'michael': 'python'
  }
            
for language in set(favorite_languages.values()): 
  print(language.title())

حالا اگر این کد را اجرا کنیم، خواهیم دید که مقادیر تکراری چاپ نمی‌شوند.

Rust 
C 
Python 
          

تأکید می‌کنم که مجموعه‌های پایتون، کالکشن‌های غیرترتیبی هستند و بنابراین، امکان دسترسی به عناصر یک مجموعه با استفاده از اندیس‌ها وجود ندارد. اگر بخواهیم به عناصر یک مجموعه با استفاده از اندیس‌ها دسترسی داشته باشیم، می‌توانیم با پاس کردن مجموعه به تابع list() آن را به یک لیست تبدیل کنیم.

کار روی مجموعه‌ها

با وجودی که نمی‌توانیم به اعضای مجموعه به طور مستقیم دسترسی داشته باشیم، اما امکان انجام کارهایی مثل حذف یا اضفه کردن عنصر به مجموعه وجود دارد. علاوه بر این، اَعمال مجموعه‌ای مانند اجتماع و اشتراک‌گیری بین مجموعه‌ها هم قابل انجام است. در اینجا با نحوه‌ی انجام این کارها روی مجموعه‌های پایتون آشنا می‌شویم.

حذف و اضافه عنصر به مجموعه

متدهای add() و remove() به ترتیب، برای اضافه کردن به و حذف عنصر از مجموعه کاربرد دارند. در مثال زیر، از این متدها استفاده شده است.

Copy Icon python_sets.py
primes = {2, 3, 5, 7}
print(primes)

primes.add(11) 
print(primes) 
            
primes.remove(2) 
print(primes) 

نتیجه‌ی اجرای این کد، به صورت زیر خواهد بود.

{2, 3, 5, 7} 
{2, 3, 5, 7, 11} 
{3, 5, 7, 11} 
          

در مورد هر یک از این متدها، باید به یک نکته توجه داشته باشید.

  • در متد add() اگر آیتمی که قصد داریم به مجموعه اضافه کنیم، در مجموعه موجود باشد، هیچ اتفاقی رخ نمی‌دهد.
  • اگر آیتمی که قصد داریم با استفاده از متد remove() حذف کنیم، در مجموعه موجود نباشد، خطا تولید خواهد شد.

اما متد دیگری با نام discard() هم داریم که عنصر مورد نظر را اگر موجود باشد، حذف می‌کند واگر موجود نباشد، گزاره نادیده گرفته شده و خطایی هم تولید نمی‌شود. به علاوه، متد pop() هم در صورت اعمال روی یک مجموعه، یک عنصر از مجموعه را به صورت تصادفی حذف می‌کند.

اَعمال مجموعه‌ای

در پایتون، اعمال مجموعه‌ای اجتماع، اشتراک، تفاضل و تفاضل متقارن روی مجموعه‌ها قابل انجام است. برای هر یک از این اعمال، یک عملگر و یک متد تدارک دیده شده که می‌توانیم از هر کدام که مایلیم، استفاده کنیم.

  • عملگر | و متد union() برای عمل اجتماع کاربرد دارند. از اجتماع دو مجموعه، یک مجموعه‌ی دیگر حاصل می‌شود که اعضایش یا در مجموعه‌ی اول یا در مجموعه‌ی دوم و یا در هر دو موجود هستند.
  • عملگر & و متد intersection() برای عمل اشتراک کاربرد دارند. حاصل اشتراک دو مجموعه، مجموعه‌ای است که اعضایش در هر دو مجموعه موجود هستند.
  • عملگر - و متد difference() برای عمل تفاضل کاربرد دارند. حاصل عمل تفاضل روی دو مجموعه، مجموعه‌ای است که اعضایش در مجموعه‌ی اول هستند اما در مجموعه‌ی دوم خیر.
  • عملگر ^ و متد symmetric_difference() برای عمل تفاضل متقارن کاربرد دارند. انجام این عمل روی دو مجموعه باعث تولید مجموعه‌ای می‌شود که اعضایش یا در مجموعه‌ی اول هستند یا در مجموعه‌ی دوم، اما در هر دو مجموعه نیستند.

در مثال زیر از این اعمال مجموعه‌ای استفاده شده است. ما از عملگرها استفاده کرده‌ایم اما نحوه‌ی استفاده از متدها هم کامنت شده است.

Copy Icon python_sets.py
first_set = {1, 2, 3}
second_set = {3, 4, 5} 
            
print(first_set | second_set)
# print(first_set.union(second_set))
            
print(first_set & second_set) 
# print(first_set.intersection(second_set))
            
print(first_set - second_set) 
# print(first_set.difference(second_set)) 
            
print(first_set ^ second_set) 
# print(first_set.symmetric_difference(second_set))

نتیجه‌ی اجرای این کد، به صورت زیر خواهد بود.

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

با وجود تغییر پذیری مجموعه‌ها، اعمال مجموعه‌ایِ بالا به صورت درجا روی مچموعه‌ها اعمال نمی‌شوند. اما برای هر یک از این اعمال، متدی وجود دارد که عمل مورد نظر را به صورت درجا روی مجموعه اعمال می‌کند: متد update() برای اجتماع، متد intersection_update() برای اشتراک، متد difference_update() برای تفاضل و متد symmetric_difference_update() برای تفاضل متقارن.

Copy Icon python_sets.py
first_set = {1, 2, 3}
second_set = {3, 4, 5} 
            
first_set.union(second_set)
print(first_set)
            
first_set.update(second_set)
print(first_set)

نتیجه‌ی اجرای این کد، به صورت زیر خواهد بود.

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

شاید انتظار داشتید که نام متد update() هم به شیوه‌ی یکسان با سه متد دیگر union_update() می‌بود. اما حقیقت ماجرا این است که نام متد update() به خاطر نقش کلی‌تری است که این متد دارد. متد update() نه فقط یک مجموعه، بلکه هر کالکشن دیگر را به عنوان آرگومان می‌پذیرد و عناصر آن را به مجموعه‌ی مورد نظر اضافه می‌کند.

بررسی عضویت یک عنصر در مجموعه

برای بررسی عضویت یا عدم عضویت یک مقدار در یک مجموعه، می‌توانیم از عملگر in استفاده کنیم. از این عملگر به فرم value in collection استفاده می‌شود. اگر value عضو collection باشد، مقدار True و در غیر این صورت، مقدار False برگردانده می‌شود.

Copy Icon python_sets
first_set = {1, 2, 3}
second_set = {3, 4, 5} 
            
print(4 in first_set)  # False
print(4 in second_set) # True 

عملگر in مختص مجموعه‌ها نیست و روی سایر کالکشن‌ها هم قابل استفاده است.