Domanda

Ho una lista di set:

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

Voglio s1 s2 ∩ ∩ s3 ...

posso scrivere una funzione per farlo eseguendo una serie di s1.intersection(s2) a coppie, ecc.

C'è una, migliore, o built-in modo raccomandato?

È stato utile?

Soluzione

Da Python versione 2.6 in poi è possibile utilizzare più argomenti per set.intersection() , come

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

Se i set sono in un elenco, questo si traduce in:

u = set.intersection(*setlist)

dove *a_list è espansione della lista

Altri suggerimenti

A partire dal 2.6, set.intersection prende arbitrariamente molti iterabili.

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

Chiaramente set.intersection è ciò che si vuole qui, ma nel caso in cui sia necessario una generalizzazione di "prendere la somma di tutte queste", "prendere il prodotto di tutti questi", "prendere la XOR di tutti questi", ciò che sei cercando è la funzione 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}

Se non si dispone di Python 2.6 o superiore, l'alternativa è quello di scrivere un esplicito ciclo:

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

È inoltre possibile utilizzare reduce:

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

Tuttavia, molti programmatori Python detestano, tra cui Guido si :

  

Circa 12 anni fa, Python acquisito lambda, ridurre (), filter () e carta (), per gentile concessione di (credo) un hacker Lisp che li perdere e ha presentato le patch di lavoro. Ma, nonostante il valore di PR, penso che queste caratteristiche dovrebbero essere tagliati da Python 3000.

     

Ora ridurre (). Questo è in realtà quello che ho sempre odiato la maggior parte, perché, a parte un paio di esempi che coinvolgono + o *, quasi ogni volta che vedo un ridurre () con un argomento di funzione non banale, ho bisogno di prendere carta e penna per schema ciò che è effettivamente immessa in tale funzione prima comprendo ciò che il ridurre () dovrebbe fare. Così nella mia mente, l'applicabilità di ridurre () è praticamente limitato a operatori associativi, e in tutti gli altri casi è meglio scrivere il ciclo di accumulazione in modo esplicito.

Qui sto offrendo una funzione generica per il set più intersezione cercando di sfruttare il miglior metodo disponibile:

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 potrebbe non gradire reduce, ma io sono un po 'affezionato:)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top