¿La mejor manera de encontrar la intersección de conjuntos múltiples?

Tengo una lista de conjuntos:

setlist = [s1,s2,s3...] 

Quiero s1 ∩ s2 ∩ s3 …

Puedo escribir una función para hacerlo ejecutando una serie de s1.intersection(s2) pares, etc.

¿Hay alguna forma recomendada, mejor, o incorporada?

    Desde la versión 2.6 de Python, puede usar múltiples argumentos para set.intersection() , como

     u = set.intersection(s1, s2, s3) 

    Si los conjuntos están en una lista, esto se traduce en:

     u = set.intersection(*setlist) 

    donde *a_list es la expansión de lista

    A partir del 2.6, set.intersection toma arbitrariamente muchos iterables.

     >>> 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]) 

    Lo que quieres aquí es claramente set.intersection , pero en caso de que necesites una generalización de “toma la sum de todos estos”, “toma el producto de todos estos”, “toma el xor de todos estos”, lo que estás buscando Porque es la función de reduce :

     from operator import and_ from functools import reduce print(reduce(and_, [{1,2,3},{2,3,4},{3,4,5}])) # = {3} 

    o

     print(reduce((lambda x,y: x&y), [{1,2,3},{2,3,4},{3,4,5}])) # = {3} 

    Si no tiene Python 2.6 o superior, la alternativa es escribir un bucle explícito para:

     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]) 

    También puedes usar reduce :

     set_list = [set([1, 2]), set([1, 3]), set([1, 4])] print reduce(lambda s1, s2: s1 & s2, set_list) # Output: set([1]) 

    Sin embargo, a muchos progtwigdores de Python les disgusta, incluido el propio Guido :

    Hace unos 12 años, Python adquirió lambda, reduce (), filter () y map (), cortesía de (creo) un hacker Lisp que los extrañó y envió parches de trabajo. Pero, a pesar del valor de PR, creo que estas características deberían eliminarse de Python 3000.

    Así que ahora reduce (). Este es en realidad el que siempre he odiado más, porque, aparte de algunos ejemplos que incluyen + o *, casi cada vez que veo una llamada a reduce () con un argumento de función no trivial, necesito agarrar lápiz y papel para diagrame lo que realmente está siendo alimentado en esa función antes de que entienda lo que se supone que hace el reduce (). Entonces, en mi opinión, la aplicabilidad de reduce () está bastante limitada a los operadores asociativos, y en todos los demás casos es mejor escribir explícitamente el bucle de acumulación.

    Aquí ofrezco una función genérica para múltiples intersecciones de conjuntos tratando de aprovechar el mejor método disponible:

     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:]) 

    A Guido no le gusta reduce , pero me gusta 🙂