أفضل طريقة للعثور على تقاطع مجموعات متعددة؟
-
23-09-2019 - |
سؤال
لدي قائمة بالمجموعات:
setlist = [s1,s2,s3...]
أريد S1 ∩ S2 ∩ S3 ...
يمكنني كتابة وظيفة للقيام بذلك عن طريق أداء سلسلة من الزوجين s1.intersection(s2)
, ، إلخ.
هل هناك طريقة موصى بها أو أفضل أو مدمجة؟
المحلول
من Python الإصدار 2.6 على يمكنك استخدام وسيطات متعددة إلى set.intersection()
, ، مثل
u = set.intersection(s1, s2, s3)
إذا كانت المجموعات في قائمة ، فإن هذا يترجم إلى:
u = set.intersection(*setlist)
أين *a_list
هو توسيع قائمة
نصائح أخرى
اعتبارا من 2.6 ، set.intersection
يأخذ بشكل تعسفي العديد من المتكررين.
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s3 = set([2, 4, 6])
>>> s1 & s2 & s3
set([2])
>>> s1.intersection(s2, s3)
set([2])
>>> sets = [s1, s2, s3]
>>> set.intersection(*sets)
set([2])
بوضوح set.intersection
هو ما تريده هنا ، ولكن في حال كنت بحاجة إلى تعميم على "خذ مجموع كل هذه" ، "خذ منتج كل هذه" ، "خذ XOR من كل هذه" ، ما تبحث عنه هو reduce
وظيفة:
from operator import and_
from functools import reduce
print(reduce(and_, [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
أو
print(reduce((lambda x,y: x&y), [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
إذا لم يكن لديك Python 2.6 أو أعلى ، فإن البديل هو كتابة حلقة صريحة:
def set_list_intersection(set_list):
if not set_list:
return set()
result = set_list[0]
for s in set_list[1:]:
result &= s
return result
set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print set_list_intersection(set_list)
# Output: set([1])
تستطيع ايضا استخذام reduce
:
set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print reduce(lambda s1, s2: s1 & s2, set_list)
# Output: set([1])
ومع ذلك ، فإن العديد من مبرمجي Python يكرهون ذلك ، بما في ذلك Guido نفسه:
منذ حوالي 12 عامًا ، قام Python Aquired Lambda ، LED () ، Filter () و MAP () ، بإذن من (أعتقد) قراصنة LISP التي فاتتها وقدمت بقع عمل. ولكن ، على الرغم من قيمة العلاقات العامة ، أعتقد أن هذه الميزات يجب قطعها من Python 3000.
حتى الآن قلل (). هذا هو في الواقع الشخص الذي كرهته دائمًا أكثر ، لأنه بصرف النظر عن بعض الأمثلة التي تنطوي على + أو *، في كل مرة أرى فيها مكالمة تقليص () مع حجة وظيفية غير تافهة ، أحتاج إلى الحصول على القلم والورق رسم تخطيطي ما يتم تغذيته بالفعل في هذه الوظيفة قبل أن أفهم ما الذي يفترض أن يفعله الحد (). لذلك في رأيي ، فإن قابلية تطبيق تقليل () تقتصر إلى حد كبير على المشغلين الترابطيين ، وفي جميع الحالات الأخرى ، من الأفضل كتابة حلقة التراكم بشكل صريح.
أنا هنا أقدم وظيفة عامة لتقاطع مجموعة متعددة في محاولة للاستفادة من أفضل طريقة متاحة:
def multiple_set_intersection(*sets):
"""Return multiple set intersection."""
try:
return set.intersection(*sets)
except TypeError: # this is Python < 2.6 or no arguments
pass
try: a_set= sets[0]
except IndexError: # no arguments
return set() # return empty set
return reduce(a_set.intersection, sets[1:])
قد يكره Guido reduce
, ، لكنني مولع به نوعًا ما :)