مج

مجموعه در Python

16 تمرین

درباره‌ی مجموعه

یک set مجموعه‌ای تغییرپذیر و نامرتب از اشیای هش‌پذیر است. اعضای مجموعه باید متمایز باشند؛ موارد تکراری مجاز نیستند. آن‌ها می‌توانند چندین نوع داده‌ی متفاوت و حتی ساختارهای تودرتو مانند یک tuple از tuplesها را در خود نگه دارند، به شرطی که همه‌ی عناصر هش‌پذیر باشند. مجموعه‌ها همچنین در گونه‌ی تغییرناپذیر frozenset هم وجود دارند.

مجموعه‌ها بیشتر برای حذف سریع موارد تکراری از دیگر ساختارهای داده یا دسته‌بندی‌های عنصر به کار می‌روند. از آن‌ها برای مقایسه‌های کارآمد هم استفاده می‌شود، زمانی که نیازی به ترتیب‌دهی و ردیابی موارد تکراری نیست.

مانند دیگر انواع مجموعه (دیکشنری‌ها، لیست‌ها، تاپل‌ها)، sets از این موارد پشتیبانی می‌کنند:

  • پیمایش با for item in <set>،
  • بررسی عضویت با in و not in،
  • محاسبه‌ی طول با len() و
  • کپی‌های سطحی با copy().

sets از این موارد پشتیبانی نمی‌کنند:

  • نمایه‌سازی از هر نوعی
  • ترتیب‌دهی از طریق مرتب‌سازی یا درج
  • برش
  • الحاق با +

بررسی عضویت در یک set (به طور میانگین) پیچیدگی زمانی ثابت دارد، در حالی که بررسی عضویت در یک list یا string با افزایش طول داده پیچیدگی زمانی رشد می‌کند. متدهایی مانند <set>.union()، <set>.intersection() یا <set>.difference() هم (به طور میانگین) پیچیدگی زمانی ثابت دارند.

ساخت مجموعه

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

لیترال‌های مجموعه

یک set را می‌توان مستقیماً به صورت یک لیترال مجموعه با آکولاد {} و کاما بین عنصرها نوشت. موارد تکراری بی‌سروصدا حذف می‌شوند:

>>> one_element = {'➕'}
{'➕'}

>>> multiple_elements = {'➕', '🔻', '🔹', '🔆'}
{'➕', '🔻', '🔹', '🔆'}

>>> multiple_duplicates =  {'Hello!', 'Hello!', 'Hello!', 
                            '¡Hola!','Привіт!', 'こんにちは!', 
                            '¡Hola!','Привіт!', 'こんにちは!'}
{'こんにちは!', '¡Hola!', 'Hello!', 'Привіт!'}

لیترال‌های مجموعه از همان آکولادهای لیترال‌های dict استفاده می‌کنند، به این معنا که برای ساختن یک set خالی باید از set() استفاده کنید.

سازنده‌ی مجموعه

set() (سازنده‌ی کلاس set) را می‌توان با هر iterable که به عنوان آرگومان داده می‌شود به کار برد. عناصر iterable یکی‌یکی پیمایش و به set اضافه می‌شوند. ترتیب عنصرها حفظ نمی‌شود و موارد تکراری بی‌سروصدا حذف می‌شوند:

# To create an empty set, the constructor must be used.
>>> no_elements = set()
set()

# The tuple is unpacked & each element is added.  
# Duplicates are removed.
>>> elements_from_tuple = set(("Parrot", "Bird", 
                               334782, "Bird", "Parrot"))
{334782, 'Bird', 'Parrot'}

# The list is unpacked & each element is added.
# Duplicates are removed.
>>> elements_from_list = set([2, 3, 2, 3, 3, 3, 5, 
                              7, 11, 7, 11, 13, 13])
{2, 3, 5, 7, 11, 13}

کامپرهنشن‌های مجموعه

مانند lists و dicts، مجموعه‌ها را می‌توان با کامپرهنشن ساخت:

# First, a list with duplicates
>>> numbers = [1,2,3,4,5,6,6,5,4,8,9,9,9,2,3,12,18]

# This set comprehension squares the numbers divisible by 3
# Duplicates are removed.
>>> calculated = {item**2 for item in numbers if item % 3 == 0}
{9, 36, 81, 144, 324}

نکات ظریف هنگام ساخت مجموعه

به دلیل رفتار «بازکردن» آن، استفاده از سازنده‌ی set با یک رشته ممکن است غافلگیرکننده باشد:

# String elements (Unicode code points) are 
# iterated through and added *individually*.
>>> elements_string = set("Timbuktu")
{'T', 'b', 'i', 'k', 'm', 't', 'u'}

# Unicode separators and positioning code points 
# are also added *individually*.
>>> multiple_code_points_string = set('अभ्यास')
{'अ', 'भ', 'य', 'स', 'ा', '्'}

به یاد داشته باشید: مجموعه‌ها می‌توانند انواع داده‌های مختلف و انواع داده‌ی تودرتو را نگه دارند، اما همه‌ی عناصر set باید هش‌پذیر باشند:

# Attempting to use a list for a set member throws a TypeError
>>> lists_as_elements = {['🌈','💦'], 
                        ['☁️','⭐️','🌍'], 
                        ['⛵️', '🚲', '🚀']}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


# Standard sets are mutable, so they cannot be hashed.
>>> sets_as_elements = {{'🌈','💦'}, 
                        {'☁️','⭐️','🌍'}, 
                        {'⛵️', '🚲', '🚀'}}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'

با این حال، می‌توان یک set از sets را با نوع frozenset() ساخت:

# Frozensets don't have a literal form.
>>> set_1 = frozenset({'🌈','💦'})
>>> set_2 = frozenset({'☁️','⭐️','🌍'})
>>> set_3 = frozenset({'⛵️', '🚲', '🚀'})

>>> frozen_sets_as_elements = {set_1, set_2, set_3}
>>> frozen_sets_as_elements
{frozenset({'⛵️', '🚀', '🚲'}),
 frozenset({'🌈', '💦'}),
 frozenset({'☁️', '⭐️', '🌍'})}

افزودن و حذف اعضای مجموعه

می‌توان عناصر را با متدهای <set>.add(<item>) و <set>.remove(<item>) به یک set افزود یا از آن حذف کرد. متد .remove(<item>) اگر عنصر در set موجود نباشد یک KeyError پرتاب می‌کند:

>>> creatures = {'crow', 'duck', 'fish', 'monkey', 'elephant'}
>>> creatures.add('beaver')
>>> creatures.remove('duck')
>>> creatures
{'beaver', 'crow', 'elephant', 'fish', 'monkey'}

# Trying to remove an item that is not present raises a KeyError
>>> creatures.remove('bear')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  KeyError: 'bear'

راهبردهای بیشتر برای حذف اعضای مجموعه

  • <set>.discard(<item>) عنصری را از set حذف می‌کند، اما اگر آن عنصر موجود نباشد KeyError پرتاب نمی‌کند.
  • <set>.clear() همه‌ی عناصر را از مجموعه حذف می‌کند.
  • <set>.pop() یک عنصر دلبخواه را حذف و برمی‌گرداند، و اگر set خالی باشد KeyError پرتاب می‌کند.

عملیات مجموعه

مجموعه‌ها متدهایی دارند که عموماً عملیات مجموعه‌های ریاضی را تقلید می‌کنند. بیشتر (نه همه‌ی) این متدها یک عملگر معادل دارند. متدها عموماً هر iterable را به عنوان آرگومان می‌پذیرند، در حالی که عملگرها لازم دارند که هر دو طرف عملیات set یا frozenset باشند.

آزمایش عضویت بین مجموعه‌ها

متد <set>.isdisjoint(<other_collection>) برای آزمایش این به کار می‌رود که آیا عناصر یک set با عناصر دیگری هم‌پوشانی دارند یا نه. این متد هر iterable یا set را به عنوان آرگومان می‌پذیرد. اگر دو مجموعه هیچ عنصر مشترکی نداشته باشند True برمی‌گرداند، و اگر عناصری مشترک باشند False.

# Both mammals and additional_animals are lists.
>>> mammals = ['squirrel','dog','cat','cow', 'tiger', 'elephant']
>>> additional_animals = ['pangolin', 'panda', 'parrot', 
                          'lemur', 'tiger', 'pangolin']

# Animals is a dict.
>>> animals = {'chicken': 'white',
               'sparrow': 'grey',
               'eagle': 'brown and white',
               'albatross': 'grey and white',
               'crow': 'black',
               'elephant': 'grey', 
               'dog': 'rust',
               'cow': 'black and white',
               'tiger': 'orange and black',
               'cat': 'grey',
               'squirrel': 'black'}
               
# Birds is a set.
>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'}

# Mammals and birds don't share any elements.
>>> birds.isdisjoint(mammals)
True

# There are also no shared elements between 
# additional_animals and birds.
>>> birds.isdisjoint(additional_animals)
True

# Animals and mammals have shared elements.
# **Note** The first object needs to be a set or converted to a set
# since .isdisjoint() is a set method.
>>> set(animals).isdisjoint(mammals)
False

بررسی زیرمجموعه و ابرمجموعه

<set>.issubset(<other_collection>) برای بررسی این به کار می‌رود که آیا هر عنصر <set> در <other_collection> هم هست یا نه. شکل عملگری آن <set> <= <other_set> است:

# Set methods will take any iterable as an argument.
# All members of birds are also members of animals.
>>> birds.issubset(animals)
True

# All members of mammals also appear in animals.
# **Note** The first object needs to be a set or converted to a set
# since .issubset() is a set method.
>>> set(mammals).issubset(animals)
True

# Both objects need to be sets to use a set operator
>>> birds <= set(mammals)
False

# A set is always a loose subset of itself.
>>> set(additional_animals) <= set(additional_animals)
True

<set>.issuperset(<other_collection>) وارون .issubset() است. از آن برای بررسی این استفاده می‌شود که آیا هر عنصر <other_collection> در <set> هم هست یا نه. شکل عملگری آن <set> >= <other_set> است:

# All members of mammals also appear in animals.
# **Note** The first object needs to be a set or converted to a set
# since .issuperset() is a set method.
>>> set(animals).issuperset(mammals)
True

# All members of animals do not show up as members of birds.
>>> birds.issuperset(animals)
False

# Both objects need to be sets to use a set operator
>>> birds >= set(mammals)
False

# A set is always a loose superset of itself.
>>> set(animals) >= set(animals)
True

زیرمجموعه و ابرمجموعه‌ی «سره»

<set> < <other_set> و <set> > <other_set> برای آزمودن زیرمجموعه‌های سره به کار می‌روند. یک set برای عملگر < یک زیرمجموعه‌ی سره است اگر (<set> <= <other_set>) و (<set> != <other_set>) برقرار باشد.

یک set برای عملگر > یک ابرمجموعه‌ی سره است اگر (<set> >= <other_set>) و (<set> != <other_set>) برقرار باشد. این عملگرها معادل متدی ندارند:

>>> animal_names = {'albatross','cat','chicken','cow','crow','dog',
                   'eagle','elephant','sparrow','squirrel','tiger'}

>>> animals_also = {'albatross','cat','chicken','cow','crow','dog',
                   'eagle','elephant','sparrow','squirrel','tiger'}

>>> mammals = {'squirrel','dog','cat','cow', 'tiger', 'elephant'}
>>> birds   = {'crow','sparrow','eagle','chicken', 'albatross'}

>>> mammals < animal_names
True

>>> animal_names > birds
True

# A set is not a *proper subset* if set == other set.
>>> animals_also < animal_names
False

# A set is never a *proper subset* of itself
>>> animals_also < animals_also
False

اجتماع مجموعه‌ها

<set>.union(*<other iterables>) یک set جدید با عناصر <set> و همه‌ی <other iterables> برمی‌گرداند. شکل عملگری این متد <set> | <other set 1> | <other set 2> | ... | <other set n> است.

>>> perennials = {'Asparagus', 'Broccoli', 'Sweet Potato', 'Kale'}
>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Summer Squash'}
>>> more_perennials = ['Radicchio', 'Rhubarb', 
                      'Spinach', 'Watercress']

# Methods will take any iterable as an argument.
>>> perennials.union(more_perennials)
{'Asparagus','Broccoli','Kale','Radicchio','Rhubarb',
'Spinach','Sweet Potato','Watercress'}

# Operators require sets.
>>> set(more_perennials) | perennials
{'Asparagus',
 'Broccoli',
 'Kale',
 'Radicchio',
 'Rhubarb',
 'Spinach',
 'Sweet Potato',
 'Watercress'}

تفاضل مجموعه‌ها

<set>.difference(*<other iterables>) یک set جدید با عناصری از <set> اصلی که در <others> نیستند برمی‌گرداند. شکل عملگری این متد <set> - <other set 1> - <other set 2> - ... - <other set n> است.

>>> berries_and_veggies = {'Asparagus', 
                          'Broccoli', 
                          'Watercress', 
                          'Goji Berries', 
                          'Goose Berries', 
                          'Ramps', 
                          'Walking Onions', 
                          'Blackberries', 
                          'Strawberries', 
                          'Rhubarb', 
                          'Kale', 
                          'Artichokes', 
                          'Currants'}

>>> veggies = ('Asparagus', 'Broccoli', 'Watercress', 'Ramps',
               'Walking Onions', 'Rhubarb', 'Kale', 'Artichokes')

# Methods will take any iterable as an argument.
>>> berries = berries_and_veggies.difference(veggies)
{'Blackberries','Currants','Goji Berries',
 'Goose Berries', 'Strawberries'}

# Operators require sets.
>>> berries_and_veggies - berries
{'Artichokes','Asparagus','Broccoli','Kale',
'Ramps','Rhubarb','Walking Onions','Watercress'}

اشتراک مجموعه‌ها

<set>.intersection(*<other iterables>) یک set جدید با عناصر مشترک بین set اصلی و همه‌ی <others> برمی‌گرداند (به عبارت دیگر، setی که همه‌چیز در آن اشتراک دارد). شکل عملگری این متد <set> & <other set> & <other set 2> & ... & <other set n> است

>>> perennials = {'Annatto','Asafetida','Asparagus','Azalea',
                 'Winter Savory', 'Broccoli','Curry Leaf','Fennel', 
                 'Kaffir Lime','Kale','Lavender','Mint','Oranges',
                 'Oregano', 'Tarragon', 'Wild Bergamot'}

>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Marjoram', 
              'Summer Squash', 'Okra','Shallots', 'Basil', 
              'Cilantro', 'Cumin', 'Sunflower', 'Chervil', 
              'Summer Savory'}

>>> herbs = ['Annatto','Asafetida','Basil','Chervil','Cilantro',
            'Curry Leaf','Fennel','Kaffir Lime','Lavender',
            'Marjoram','Mint','Oregano','Summer Savory', 
            'Tarragon','Wild Bergamot','Wild Celery',
            'Winter Savory']


# Methods will take any iterable as an argument.
>>> perennial_herbs = perennials.intersection(herbs)
{'Annatto', 'Asafetida', 'Curry Leaf', 'Fennel', 'Kaffir Lime',
 'Lavender', 'Mint', 'Oregano', 'Wild Bergamot','Winter Savory'}

# Operators require both groups be sets.
>>> annuals & set(herbs)
 {'Basil', 'Chervil', 'Marjoram', 'Cilantro'}

تفاضل متقارن مجموعه‌ها

<set>.symmetric_difference(<other iterable>) یک set جدید برمی‌گرداند که شامل عناصری است که در <set> یا <other> هستند، اما نه در هر دو. شکل عملگری این متد <set> ^ <other set> است.

>>> plants_1 = {'🌲','🍈','🌵', '🥑','🌴', '🥭'}
>>> plants_2 = ('🌸','🌴', '🌺', '🌲', '🌻', '🌵')


# Methods will take any iterable as an argument.
>>> fruit_and_flowers = plants_1.symmetric_difference(plants_2)
>>> fruit_and_flowers
{'🌸', '🌺', '🍈', '🥑', '🥭','🌻' }


# Operators require both groups be sets.
>>> fruit_and_flowers ^ plants_1
{'🌲',  '🌸', '🌴', '🌵','🌺', '🌻'}

>>> fruit_and_flowers ^ set(plants_2)
{'🥭', '🌴', '🌵', '🍈', '🌲', '🥑'}
Note

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

برای به دست آوردن فقط عناصر منحصربه‌فرد در هر set در آن سری، باید اشتراک‌های بین همه‌ی ترکیب‌های دوتایی مجموعه‌ها در مرحله‌ای جداگانه جمع و حذف شوند:

>>> one = {'black pepper','breadcrumbs','celeriac','chickpea flour',
           'flour','lemon','parsley','salt','soy sauce',
           'sunflower oil','water'}

>>> two = {'black pepper','cornstarch','garlic','ginger',
           'lemon juice','lemon zest','salt','soy sauce','sugar',
           'tofu','vegetable oil','vegetable stock','water'}

>>> three = {'black pepper','garlic','lemon juice','mixed herbs',
             'nutritional yeast', 'olive oil','salt','silken tofu',
             'smoked tofu','soy sauce','spaghetti','turmeric'}

>>> four = {'barley malt','bell pepper','cashews','flour',
            'fresh basil','garlic','garlic powder', 'honey',
            'mushrooms','nutritional yeast','olive oil','oregano',
            'red onion', 'red pepper flakes','rosemary','salt',
            'sugar','tomatoes','water','yeast'}

>>> intersections = (one & two | one & three | one & four | 
                     two & three | two & four | three & four)
...
{'black pepper','flour','garlic','lemon juice','nutritional yeast', 
'olive oil','salt','soy sauce', 'sugar','water'}

# The ^ operation will include some of the items in intersections, 
# which means it is not a "clean" symmetric difference - there
# are overlapping members.
>>> (one ^ two ^ three ^ four) & intersections
{'black pepper', 'garlic', 'soy sauce', 'water'}

# Overlapping members need to be removed in a separate step
# when there are more than two sets that need symmetric difference.
>>> (one ^ two ^ three ^ four) - intersections
...
{'barley malt','bell pepper','breadcrumbs', 'cashews','celeriac',
  'chickpea flour','cornstarch','fresh basil', 'garlic powder',
  'ginger','honey','lemon','lemon zest','mixed herbs','mushrooms',
  'oregano','parsley','red onion','red pepper flakes','rosemary',
  'silken tofu','smoked tofu','spaghetti','sunflower oil', 'tofu', 
  'tomatoes','turmeric','vegetable oil','vegetable stock','yeast'}
ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود

مجموعه را یاد بگیرید

تمرین کردن قفل شده است

برای تمرین مجموعه قفل 4 تمرین دیگر را باز کنید