flowchart BT Container[<b>الحاوي</b><br>Container] Sized[<b>المحجَّم</b><br>Sized] Iterable[<b>القابل للكر</b><br>Iterable] Collection[<b>الجمع</b><br>Collection] Set[<b>المجموعة</b> <br>Set] set[<b>المجموعة</b> <br><code>set</code>] MutableSet[<b>المجموعة المتغيرة</b> <br>MutableSet] frozenset[<b>المجموعة الجامدة</b> <br><code>frozenset</code>] Collection --> Container Collection --> Sized Collection --> Iterable Set --> Collection frozenset --> Set MutableSet --> Set set --> MutableSet
ملحق H — المجموعة
شجرة أنواع المجموعة في بايثون.
للتفصيل راجع خريطة الجموع: شكل P.1
المجموعة (set
) هي جمع متغير من عناصر مرقَّمة فريدة بلا ترتيب.
- متغير: يعني أنها تقبل الإضافة والحذف والتعديل
- مرقَّمة: فيكون لكل عنصر رقم هو ناتج عن عملية التجزئة (Hash)
- فريدة: يعني أن العنصر لا يتكرر فيها
- بلا ترتيب: فليس للعنصر موضِع (0, 1, 2 …) كما هو الحال في الجمع المرتَّب
أو بالقوسين المتعرجين {}
أو بالإجراء المُنشئ set()
على النحو التالي:
= {10, 20, 30}
s = set((10, 20, 30))
s1 = set([10, 20, 30])
s2 = set(range(10, 30+1, 10))
s3 assert s == s1 == s2 == s3
تقبل المجموعة -لكونها من نوع الجمع (Collection)- العمليات التالية:
- العد:
len(s)
- التكرار:
for x in s
- العضوية:
x not in s
وباعتبارها مجموعة متغيرة (MutableSet)، فإنها تقبل الإجراءات التالية:
- الإضافة:
add
- الحذف:
discard
- نزع عنصر عشوائي:
pop
- المحو:
clear
وإليك جدول طرق المجموعة:
الفعل | عمله |
---|---|
set.add(elem) |
يضيف العنصر elem إلى المجموعة. |
set.remove(elem) |
يزيل العنصر elem من المجموعة. يرفع خطأ KeyError إذا لم يكن elem موجودًا. |
set.discard(elem) |
يزيل العنصر elem من المجموعة إذا كان موجودًا. |
set.pop() |
يزيل ويعيد عنصرًا عشوائيًا من المجموعة. |
set.clear() |
يزيل جميع العناصر من المجموعة. |
set.update(*others) |
يقوم بتحديث المجموعة بإضافة جميع العناصر من المجموعات الأخرى. |
set.intersection(*others) |
ترجع مجموعة جديدة تحتوي على العناصر المشتركة بين المجموعة والمجموعات الأخرى. |
set.intersection_update(*others) |
تقوم بتحديث المجموعة بإبقاء العناصر الموجودة في المجموعة والمجموعات الأخرى فقط. |
set.difference(*others) |
ترجع مجموعة جديدة تحتوي على العناصر الموجودة في المجموعة ولكنها غير موجودة في المجموعات الأخرى. |
set.difference_update(*others) |
تقوم بتحديث المجموعة بإزالة العناصر الموجودة في المجموعات الأخرى. |
set.symmetric_difference(other) |
ترجع مجموعة جديدة تحتوي على العناصر الموجودة في المجموعة أو المجموعة الأخرى ولكن ليس في كليهما. |
set.symmetric_difference_update(other) |
تقوم بتحديث المجموعة بإبقاء العناصر الموجودة في المجموعة أو المجموعة الأخرى ولكن ليس في كليهما. |
set.isdisjoint(other) |
ترجع True إذا لم يكن للمجموعة أي عناصر مشتركة مع المجموعة الأخرى، و False خلاف ذلك. |
set.issubset(other) |
ترجع True إذا كانت المجموعة مجموعة فرعية من المجموعة الأخرى، و False خلاف ذلك. |
set.issuperset(other) |
ترجع True إذا كانت المجموعة مجموعة شاملة للمجموعة الأخرى، و False خلاف ذلك. |
set.copy() |
ترجع نسخة سطحية من المجموعة. |
ولا يشترط تجانس العناصر؛ بل يجوز أن تكون أنواعها مختلفة:
= {10, 20, 'hello', True, (300, 400)} s
ونرى عمليات المجموعة عليها: العد، والعضوية والتكرار:
assert len(s) == 5
assert 'hello' in s
assert 300 not in s
assert (300, 400) in s
for x in s:
print(x)
True
hello
20
(300, 400)
10
وكون المجموعة غير مرتبة، فإنها لا تسجل موقع العنصر أو ترتيب إدراجه. وبالتالي، فإنها لا تقبل الإشارة (xs[i]
) أو التقطيع (xs[i:j]
) أو أي سلوك يشبه المتسلسلات. لاحظ الخطأ التالي:
= {10, 20, 30}
xs 0] xs[
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[4], line 2 1 xs = {10, 20, 30} ----> 2 xs[0] TypeError: 'set' object is not subscriptable
التحقق السريع
عرفنا أن المجموعة تقبل إجراء العضوية x in s
، ولكن ثمة خصوصية لهذا الإجراء في المجموعة. وهذه الخصوصية تكمن في سرعة هذا الإجراء في المجموعة مقارنة بسرعة عمله في المجموعة المرتبة.
فهذه المقارنة تكون بالمجموعة {}
:
= {"192.168.1.1", "10.0.0.5", "172.16.0.2"}
black_set = "10.0.0.5"
ip if ip in black_set:
print("Access Denied")
Access Denied
وتكون كذلك في القائمة []
:
= ["192.168.1.1", "10.0.0.5", "172.16.0.2"]
black_list = "10.0.0.5"
ip if ip in black_list:
print("Access Denied")
Access Denied
لكن الفرق هو تفاصيل هذه العملية، إذ تختلف الكيفية خلف الكواليس. ولن يكون الفرق في السرعة واضحًا إلا حين تكون المجموعة كبيرة جدًّا.
- وذلك أننا في القائمة نحتاج أن نمر على العناصر واحدًا تلو الآخر، حتى نجد العنصر أو لا نجده
- أما في المجموعة، فإن القيمة يتم تجزئتها (
hash
) حتى يُعرف رقم العنصر في المجموعة مباشرة من غير المرور على عناصرها. فعملية التجزئة هذه تعطينا العنوان بشكل رياضي.
وهذا يدخل في دراسة الخوارزميات وهيكلة البيانات. فإن أردت مزيد تفصيل فراجع هذه المادة: W3Schools DSA Hash Sets.
منطق المجموعة الرياضية
مما تتميز به المجموعة عن بقية أنواع الجمع: قبولها المنطق الرياضي على النحو التالي:
- التقاطع والاتحاد والفرق، والفرق التماثلي
- وكذلك تحقق: (الجزئية والشمول والانفاصل).
وهذه القطعة مثال لجميع هذه العمليات الرياضية:
= {1, 2, 3, 4, 5}
set1 = {4, 5, 6, 7, 8} set2
العمليات على المجموعات
الاتحاد
set.union(set1, set2)
{1, 2, 3, 4, 5, 6, 7, 8}
التقاطع
set.intersection(set1, set2)
{4, 5}
الفرق
set.difference(set1, set2)
{1, 2, 3}
set.difference(set2, set1)
{6, 7, 8}
الفرق التماثلي
set.symmetric_difference(set1, set2)
{1, 2, 3, 6, 7, 8}
ملاحظة: لكل من الإجراءات السابقة علامة تمثله كما هو موضَّح في الجدول. إلا أن استعمال اسم الإجراء يقبل أي نوع من المتكررات (Iterables) ولا تقتصر على نوع المجموعة فقط (set
):
العملية | العلامة | الإجراء المكافئ |
---|---|---|
الاتحاد | set1 | set2 |
set1.union(set2) |
التقاطع | set1 & set2 |
set1.intersection(set2) |
الفرق | set1 - set2 |
set1.difference(set2) |
الفرق التماثلي | set1 ^ set2 |
set1.symmetric_difference(set2) |
العلاقات بين المجموعات
الجزئية والشمول
وكذلك لدينا إجراءات تحقق الجزئية والشمول والانفصال:
العملية | العلامة | الإجراء المكافئ |
---|---|---|
تحقق الجزئية (جزء من) | set1 <= set2 |
set1.issubset(set2) |
تحقق الشمول (يشمل) | set1 >= set2 |
set1.issuperset(set2) |
تحقق الانفصال (عدم التقاطع) | len(set1 & set2) == 0 |
set1.isdisjoint(set2) |
= {1, 2, 3}
A = {1, 2, 3, 4, 5, 6} B
وهذا مثال لاستعمالها كما في الجدول:
assert A.issubset(B)
assert B.issuperset(A)
الانفصال
وأما الانفصال، فهو عدم وجود أدنى تقاطع بين المجموعتين:
= {'Apple', 'Banana'}
C assert C.isdisjoint(A)
assert C.isdisjoint(B)