Come faccio ad aggiungere il contenuto di un iterabile a un set?


Risposte:


228

Puoi aggiungere elementi di lista a setcome questo:

>>> foo = set(range(0, 4))
>>> foo
set([0, 1, 2, 3])
>>> foo.update(range(2, 6))
>>> foo
set([0, 1, 2, 3, 4, 5])

2
Ho appena guardato indietro alla mia sessione di interprete e in realtà l'ho provato, ma ho pensato che avesse aggiunto l'intero elenco come elemento dell'insieme a causa delle parentesi quadre nella rappresentazione dell'insieme. Non avevo mai notato prima che fossero rappresentati così.
Ian Mackinnon,

7
Tale rappresentazione ti consente di incollarlo subito in una sessione interattiva, perché il setcostruttore prende un iterabile come argomento.
Frank Kusters il

3
Si noti che la rappresentazione è solo ad esempio {1, 2, 3}in Python 3 mentre era set([1, 2, 3])in Python 2.
Radon Rosborough,

40

A beneficio di chiunque possa credere, ad esempio, che fare aset.add()in un ciclo avrebbe prestazioni competitive rispetto al fare aset.update(), ecco un esempio di come è possibile verificare rapidamente le proprie convinzioni prima di diventare pubbliche:

>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "a.update(it)"
1000 loops, best of 3: 294 usec per loop

>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "for i in it:a.add(i)"
1000 loops, best of 3: 950 usec per loop

>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "a |= set(it)"
1000 loops, best of 3: 458 usec per loop

>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "a.update(it)"
1000 loops, best of 3: 598 usec per loop

>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "for i in it:a.add(i)"
1000 loops, best of 3: 1.89 msec per loop

>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "a |= set(it)"
1000 loops, best of 3: 891 usec per loop

Sembra che il costo per articolo dell'approccio ad anello sia oltre TRE volte quello updatedell'approccio.

L'utilizzo |= set()costa circa 1,5 volte ciò che updatefa, ma la metà di ciò che fa l'aggiunta di ogni singolo elemento in un ciclo.


14

È possibile utilizzare la funzione set () per convertire un iterabile in un set, quindi utilizzare l'operatore di aggiornamento set standard (| =) per aggiungere i valori univoci dal nuovo set a quello esistente.

>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])

5
L'utilizzo .updateha il vantaggio che l'argomento può essere qualsiasi iterabile, non necessariamente un insieme, a differenza dell'RHS |=dell'operatore nel tuo esempio.
tzot,

1
Buon punto. È solo una scelta estetica poiché set () può convertire un iterabile in un set, ma il numero di sequenze di tasti è lo stesso.
gbc,

Non ho mai visto quell'operatore prima, mi divertirò ad usarlo quando si aprirà in futuro; Grazie!
Eipxen,

1
@eipxen: c'è |per l'unione, &per l'intersezione e ^per ottenere elementi che si trovano nell'uno o nell'altro ma non in entrambi. Ma in un linguaggio tipizzato in modo dinamico in cui a volte è difficile leggere il codice e conoscere i tipi di oggetti che volano in giro, mi sento titubante a usare questi operatori. Qualcuno che non li riconosce (o forse non si rende nemmeno conto che Python consente agli operatori come questi) potrebbe essere confuso e pensare che siano in corso delle strane operazioni bit per bit o logiche. Sarebbe bello se anche questi operatori lavorassero su altri iterabili ...
ArtOfWarfare il

Ho eseguito alcuni test del tempo su questo .update()e aggiungi singoli elementi in un ciclo. Ho scoperto che .update()era più veloce. Ho aggiunto i miei risultati a questa risposta esistente: stackoverflow.com/a/4046249/901641
ArtOfWarfare

4

Solo un rapido aggiornamento, i tempi usando Python 3:

#!/usr/local/bin python3
from timeit import Timer

a = set(range(1, 100000))
b = list(range(50000, 150000))

def one_by_one(s, l):
    for i in l:
        s.add(i)    

def cast_to_list_and_back(s, l):
    s = set(list(s) + l)

def update_set(s,l):
    s.update(l)

i risultati sono:

one_by_one 10.184448844986036
cast_to_list_and_back 7.969255169969983
update_set 2.212590195937082

0

Usa la comprensione dell'elenco.

Cortocircuito la creazione di iterabile utilizzando un elenco, ad esempio :)

>>> x = [1, 2, 3, 4]
>>> 
>>> k = x.__iter__()
>>> k
<listiterator object at 0x100517490>
>>> l = [y for y in k]
>>> l
[1, 2, 3, 4]
>>> 
>>> z = Set([1,2])
>>> z.update(l)
>>> z
set([1, 2, 3, 4])
>>> 

[Modifica: mancata la parte impostata della domanda]


1
Non vedo alcun set? Mi sto perdendo qualcosa?
Ian Mackinnon,

-2
for item in items:
   extant_set.add(item)

Per la cronaca, penso l'affermazione che "Dovrebbe esserci uno - e preferibilmente solo un - modo obsoleto di farlo". è falso. Presuppone che molte persone di mentalità tecnica fanno, che tutti pensano allo stesso modo. Ciò che è ovvio per una persona non è così evidente per un'altra.

Direi che la mia soluzione proposta è chiaramente leggibile e fa quello che chiedi. Non credo che ci siano hit di performance coinvolti, anche se ammetto che potrei perdere qualcosa. Ma nonostante tutto, potrebbe non essere ovvio e preferibile a un altro sviluppatore.


Argh! Il ciclo for che si trova su una riga del genere sta formattando nella mia risposta - non lo farei mai. Mai.
Jaydel,

Hai assolutamente ragione. Ho modificato il post per riparare il mio danno. Grazie :)
jaydel,

9
Ti manca il punto che aset.update(iterable)scorre alla velocità C mentre for item in iterable: aset.add(item)scorre alla velocità Python, con una ricerca del metodo e una chiamata del metodo (aarrgghh !!) per articolo.
John Machin,

1
Mi dispiace, non ha detto nulla sulla performance nella sua domanda, quindi non me ne sono preoccupato.
Jaydel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.