24-05-2018, 07:16 PM
المجموعات set
المجموعات قريبة من القواميس من ناحية امكانية اجراء اختبار الانتماء او الوصول الى مختلف هناصر المجموعة او تعديلها او حذفها، كل هذا بشكل مستقل عن عدد العناصر. المجموعات هي أيضا كائنات قابلة للتعديل، لكن على خلاف القواميس، لا تخزن المجموعات سوى مفاتيح فريدة أي ليس هناك قيم تقابلها. يمكن التساؤل هنا: وما فائدة المجموعات إذا؟في الواقع، تم تحسين أداء المجموعات وقد وقع تطويرها من أجل غايات محددة، من بينها الاحتفاظ فقط بالعناصر الفريدة غير المكررة من متتالية، حيث لو قمنا بتأليف مجموعة من عناصر متتالية سنحصل فقط على عناصر فريدة غير مكررة. مهمة ثانية يتم فيها استخدام المجموعات بكثرة وهي اجراء اختبارات انتماء على عناصر متتالية.
- المجموعات هي كائنات قابلة للتعديل بمعنى امكانية تحريرها دون نسخ لكنها تتكون من عناصر hashable أي غير قابلة للتعديل. في المجموعات يمكننا إذا حفظ أعداد، وسلاسل نصية وصفوف (بشرط عدم تكونها من عناصر قابلة للتعديل)، لكن لا يمكننا حفظ الكائنات القابلة للتعديل ومنها القوائم والقواميس والمجموعات.
## تكوين مجموعة
كود :
s = set() # تكوين مجموعة فارغة
type(s) # set
s = {1, 2, 3, 'a', 18.5, False} # لاحظ أنه لا يمكننا تكوين مجموعة فارغة بواسطة {} فارغين
type(s) # والسبب ان بيثون سيعتبر الـ{} قاموسا فارغا
كود :
d = {'A':65, 'B':66, 'C':67}
type(d) # dict
set(d) # {'A', 'B', 'C'}
كود :
a = [1, 2, 4, 1, 18, 30, 4, 1]
set(a) # {1, 2, 4, 18, 30}
كود :
ss = {(1, 2, (3, 4))} # Correct
ss = {(1, 2, [3, 4])} # Error: unhashable type: 'list'
ss = {{1, 2}} # Error: unhashable type: 'set'
### الدالة len
كود :
len(s) # للحصول على عدد العناصر
كود :
'a' in s # True
'b' in s # False
كود :
s.add('Zaid') # اضافة عنصر
print(s) # {True, 2, 3, 'a', 18.5, 'Zaid'}
تقوم هذه الوظيفة بتحيين مجموعة وهي لا تضيف سوى العناصر غير الموجودة مسبقا:
كود :
s.update([1, 1, 1, 2, 3, 4, 5, 5, 6, 'Zaid', 'Amr'])
print(s) # {False, 1, 2, 3, 4, 5, 6, 'a', 'Amr', 18.5, 'Zaid'}
كود :
s.discard('Zaid') # حذف عنصر
s # {False, 1, 2, 3, 4, 5, 6, 'a', 'Amr', 18.5}
s.discard('foo') # الوظيفة تعمل حتى لو كان العنصر المراد حذفه غير موجود
كود :
s.remove('Amr') # حذف عنصر
s.remove('foo') # هنا سيطلق بيثون استثناء
try:
s.remove('foo')
except KeyError as e:
print("remove raised exception:", e)
### الوظيفة pop
رأينا هذه الوظيفة على المتتاليات، حيث تحذف وترد لنا العنصر الذي قدمنا مؤشره كوسيط. بدون وسيط تحذف pop العنصر الأخير وترده لنا. تذكير:
كود :
myList = list(s) # تحويل المجموعة الى قائمة
myList # [False, 1, 2, 3, 4, 5, 6, 'a', 18.5]
myList.pop(7) # 'a' حذف العنصر
myList # [False, 1, 2, 3, 4, 5, 6, 18.5]
myList.pop() # 18.5
myList # [False, 1, 2, 3, 4, 5, 6]
كود :
try:
s.pop()
except KeyError as e:
print(e)
تحذف جميع العناصر دفعة واحدة
كود :
s.clear()
s
كود :
s1 = {1, 2, 3}
s2 = {3, 4, 5}
s1 - s2 # difference
s1 | s2 # union
s1 & s2 # intersection
s1 == s2 # False
s1 <= s2 # inclusion
s1 < s2 # inclusion
عندما يرغب المبرمج في اجراء عملية بحث في مجموعة كبيرة من البيانات، لابد أن يتساءل عن أفضل طريقة لربح الوقت وللتقليل من استهلاك موارد النظام، الخ... سنجري مقارنة بين عملية بحث داخل قائمة واخرى داخل مجموعة (هنا استخدمت مفسر ipython):
كود :
a = [0] # قائمة ليس بها سوى عنصر واحد
s = set(a) # مجموعة انطلاقا من القائمة
%timeit -n 50 0 in a # تكرار 50 مرة على القائمة
%timeit -n 50 0 in s # تكرار 50 مرة على المجموعة
عملية البحث في المجموعات تتبع تمشيا مختلفاتماما : باعتبار المجموعات مبنية على جدول هاش (كالقواميس) فالبحث يتمثل في عمليات حسابية تقوم بها دالة هاش. دالة الهاش في المجموعة لا تستهلك عمليا سوى وقت الوصول الى عنصر واحد من عناصر القائمة، نستنتج من ذلك أن تحويل القائمة الى مجموعة قبل عملية المقارنة مفيد مهما كان حجم القائمة، لكنك قد تتساءل كم نحتاج من الوقت لتحويل متتالية الى مجموعة؟ سيحتاج التحويل الى الوقت الذي تحتاجه دالة الهاش في عملياتها على كل عنصر وهو اساسا الوقت اللازم لتصفح المتتالية مرة واحدة اذا أجريت بحثا عن كائن غير موجود في المتتالية، وبالتالي يبقى التحويل الى مجموعة أفضل وأكثر مردودية عند الرغبة في اختبار انتماء عنصر الى متتالية.
إذا كنت تستخدم ipython يمكنك أن تجرب هذين المثالين كل على حده لتقارن الوقت: بالنسبة لي استغرق انشاء المجموعة والبحث داخلها نصف الوقت الذي استغرقه البحث في القائمة رغم أنه تم انشاؤها مسبقا (تحذير: احفظ ملفاتك قبل التجربة، قد يتسبب السكربت في توقف الجهاز عن الاستجابة):
كود :
l = [i for i in range(50000000)] # قائمة كبيرة جدا
%%timeit -n 1
for i in range(49999990,50000000):
if i in l:
print(i, "in list")
كود :
%%timeit -n 1
s = set(l)
for i in range(49999990,50000000):
if i in s:
print(i, "in set")
المجموعات هي أنواع قابلة للتعديل كما رأينا أعلاه، لذلك لا يمكننا تكوين مجموعة من المجموعات. لهذا السبب تم بناء الدالة frozenset. هذه الدالة تنشئ لنا مجموعة غير قابلة للتعديل يمكننا بالتالي استخدامها كمفتاح في قاموس او مجموعة فرعية داخل مجموعة. لا يوجد طريقة مختصرة لانشائها عبر اقواس مثلا، ولابد من استخدام frozenset. من بين الوظائف المستبعدة في frozenset يمكننا ذكر update - pop - clear - remove - discard. كل هذه الوظائف جُعلت لاجراء التعديلات على المجموعات (وغيرها) وهي بالتالي غير متوفرة في frozenset.
كود :
fset = frozenset() # فارغة
fset # frozenset()
type(fset)
vowels = ('a', 'e', 'i', 'o', 'u') # frozenset صف سنحوله الى
fset = frozenset(vowels)
fset # frozenset({'a', 'e', 'i', 'o', 'u'})
d = {'A':65, 'B':66, 'C':67} # frozenset قاموس سنحوله الى
fset = frozenset(d)
fset # frozenset({'A', 'B', 'C'})
https://docs.python.org/3/library/stdtyp...-frozenset