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.