J'ai une liste d'ensembles:
setlist = [s1,s2,s3...]
Je veux s1 ∩ s2 ∩ s3 ...
Je peux écrire une fonction pour le faire en effectuant une série de paires s1.intersection(s2)
, etc.
Existe-t-il une méthode recommandée, meilleure ou intégrée?
J'ai une liste d'ensembles:
setlist = [s1,s2,s3...]
Je veux s1 ∩ s2 ∩ s3 ...
Je peux écrire une fonction pour le faire en effectuant une série de paires s1.intersection(s2)
, etc.
Existe-t-il une méthode recommandée, meilleure ou intégrée?
Réponses:
À partir de Python version 2.6, vous pouvez utiliser plusieurs arguments pour set.intersection()
, comme
u = set.intersection(s1, s2, s3)
Si les ensembles sont dans une liste, cela se traduit par:
u = set.intersection(*setlist)
où *a_list
est l' expansion de la liste
Notez que ce set.intersection
n'est pas une méthode statique, mais cela utilise la notation fonctionnelle pour appliquer l'intersection du premier ensemble avec le reste de la liste. Donc, si la liste d'arguments est vide, cela échouera.
Depuis 2.6, set.intersection
prend arbitrairement de nombreux itérables.
>>> 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])
C'est clairement set.intersection
ce que vous voulez ici, mais au cas où vous auriez besoin d'une généralisation de "prendre la somme de tout cela", "prendre le produit de tout cela", "prendre le xor de tout cela", ce que vous cherchez c'est le reduce
fonction:
from operator import and_
from functools import reduce
print(reduce(and_, [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
ou
print(reduce((lambda x,y: x&y), [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
Si vous n'avez pas Python 2.6 ou supérieur, l'alternative est d'écrire une boucle for explicite:
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])
Vous pouvez également utiliser reduce
:
set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print reduce(lambda s1, s2: s1 & s2, set_list)
# Output: set([1])
Cependant, de nombreux programmeurs Python ne l'aiment pas, y compris Guido lui - même :
Il y a environ 12 ans, Python a acquis lambda, Reduce (), filter () et map (), gracieuseté (je crois) d'un pirate Lisp qui les a manqués et a soumis des correctifs de travail. Mais, malgré la valeur PR, je pense que ces fonctionnalités devraient être coupées de Python 3000.
Alors maintenant, réduisez (). C'est en fait celui que j'ai toujours détesté le plus, car, à l'exception de quelques exemples impliquant + ou *, presque chaque fois que je vois un appel Reduce () avec un argument de fonction non trivial, je dois saisir un stylo et du papier pour diagramme ce qui est réellement introduit dans cette fonction avant de comprendre ce que la fonction de réduction () est censée faire. Donc, dans mon esprit, l'applicabilité de Reduce () est à peu près limitée aux opérateurs associatifs, et dans tous les autres cas, il est préférable d'écrire explicitement la boucle d'accumulation.
result
est vide.
Ici, je propose une fonction générique pour l'intersection de plusieurs ensembles en essayant de tirer parti de la meilleure méthode 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:])
Guido pourrait ne pas aimer reduce
, mais je l'aime un peu :)
sets
au lieu d'essayer d'accéder sets[0]
et d'attraper le IndexError
.
a_set
est utilisé lors du retour final.
return reduce(sets[0], sets[1:]) if sets else set()
?
try
/ except
. C'est une odeur de code, est inefficace et peut cacher d'autres problèmes.
reduce
est "limitée aux opérateurs associatifs", ce qui est applicable dans ce cas.reduce
est très souvent difficile à comprendre, mais ce&
n'est pas si mal.