سؤال

لدي قائمة بالمجموعات:

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, ، لكنني مولع به نوعًا ما :)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top