Aggiungi lista da impostare?


242

Testato sull'interprete Python 2.6:

>>> a=set('abcde')
>>> a
set(['a', 'c', 'b', 'e', 'd'])
>>> l=['f','g']
>>> l
['f', 'g']
>>> a.add(l)
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    a.add(l)
TypeError: list objects are unhashable

Penso di non poter aggiungere l'elenco al set perché Python non può dire se ho aggiunto due volte lo stesso elenco. C'è una soluzione?

EDIT: voglio aggiungere la lista stessa, non i suoi elementi.


2
Vuoi aggiungere l'elenco al set o gli elementi nell'elenco?
pkit,

La lista stessa - Voglio avere una serie di liste.
Adam Matan,

Sembra che la risposta più adatta sia quella sottovalutata, suggerendo di usare aSet.add (id (lst)) prima di aggiungere lst stesso ad un elenco / coda / etc, per essere sicuro di averlo fatto. È necessario riconsiderare la risposta accettata.
Rustam A.

Risposte:


187

Non è possibile aggiungere un elenco a un set perché gli elenchi sono modificabili, il che significa che è possibile modificare il contenuto dell'elenco dopo averlo aggiunto al set.

Puoi comunque aggiungere tuple al set, perché non puoi cambiare il contenuto di una tupla:

>>> a.add(('f', 'g'))
>>> print a
set(['a', 'c', 'b', 'e', 'd', ('f', 'g')])

Edit : qualche spiegazione: La documentazione definisce setcome una collezione non ordinata di oggetti hashable distinti. Gli oggetti devono essere hashabili in modo che la ricerca, l'aggiunta e la rimozione di elementi possano essere eseguite più rapidamente che guardare ogni singolo elemento ogni volta che si eseguono queste operazioni. Gli algoritmi specifici utilizzati sono spiegati nell'articolo di Wikipedia . Gli algoritmi di hashing Pythons sono spiegati su effbot.org e la __hash__funzione pythons nel riferimento python .

Alcuni fatti:

  • Gli elementi impostati e le chiavi del dizionario devono essere hash
  • Alcuni tipi di dati non lavabili:
    • list: usa tupleinvece
    • set: usa frozensetinvece
    • dict: non ha una controparte ufficiale, ma ci sono alcune ricette
  • Le istanze degli oggetti sono hash per impostazione predefinita con ogni istanza con un hash univoco. È possibile ignorare questo comportamento come spiegato nel riferimento di Python.

6
E se mai vuoi aggiungere un set a un set, usa frozenset.
FogleBird,

4
collections.namedtuplepotrebbe essere considerata la controparte "ufficiale" della dict.
SilentGhost,

1
@Wahnfrieden: che sta aggiungendo il contenuto di un set, non il set stesso.
Otto Allmendinger,

@aehlke: No, questo aggiunge gli elementi del set al primo set, ma stiamo parlando dell'aggiunta di un set come elemento del primo set.
Jeff Learman,

578

Usa set.update()o|=

>>> a = set('abc')
>>> l = ['d', 'e']
>>> a.update(l)
>>> a
{'e', 'b', 'c', 'd', 'a'}

>>> l = ['f', 'g']
>>> a |= set(l)
>>> a
{'e', 'b', 'f', 'c', 'd', 'g', 'a'}

modifica: se vuoi aggiungere l'elenco stesso e non i suoi membri, devi purtroppo usare una tupla. I membri del set devono essere hash .


set.update () aggiunge l'elenco al set, giusto? a cosa serve l'operatore pipe uguale?
FistOfFury

Rispetto ai set, l' |operatore implementa l' operazione di unione set . Sia l' |=operatore che il set.update()metodo applicano tale operazione sul posto e sono effettivamente sinonimi. Quindi, set_a |= set_bpotrebbe essere considerato zucchero sintattico per entrambi set_a.update(set_b) e set_a = set_a | set_b (tranne che in quest'ultimo caso, lo stesso set_aoggetto viene riutilizzato anziché riassegnato). </ahem>
Cecil Curry,

76

Per aggiungere gli elementi di un elenco a un set , utilizzareupdate

Da https://docs.python.org/2/library/sets.html

s.update (t): restituisce set s con elementi aggiunti da t

Per esempio

>>> s = set([1, 2])
>>> l = [3, 4]
>>> s.update(l)
>>> s
{1, 2, 3, 4}

Se invece desideri aggiungere l'intero elenco come singolo elemento al set, non puoi perché gli elenchi non sono hash. È possibile invece aggiungere una tupla, ad es s.add(tuple(l)). Vedi anche TypeError: unhashable type: 'list' quando si utilizza la funzione set integrata per ulteriori informazioni al riguardo.


40

Speriamo che questo aiuti:

>>> seta = set('1234')
>>> listb = ['a','b','c']
>>> seta.union(listb)
set(['a', 'c', 'b', '1', '3', '2', '4'])
>>> seta
set(['1', '3', '2', '4'])
>>> seta = seta.union(listb)
>>> seta
set(['a', 'c', 'b', '1', '3', '2', '4'])

15

Si prega di notare la funzione set.update(). La documentazione dice:

Aggiorna un set con l'unione di se stesso e degli altri.


5
Questo non risponde alla domanda (dal momento che l'OP vuole aggiungere l'elenco stesso al set) ma era la risposta di cui avevo bisogno quando Google mi ha portato qui :-)
tom stratton,

1
Bene, mi sembra la risposta più pertinente alla domanda ... per esempio, se b = set ([1]), b.update ([7,25]) darà a b il seguente valore: set ([ 1, 25, 7]) ---> Non è quello che stiamo cercando qui?
Louis LC,

8

gli oggetti dell'elenco non sono lavabili . potresti volerli trasformare in tuple però.


5

I set non possono avere elementi / membri mutabili (modificabili). Un elenco, essendo mutabile, non può essere un membro di un set.

Poiché i set sono mutabili, non puoi avere un set di set! Puoi avere una serie di frozenset però.

(Lo stesso tipo di "requisito di mutabilità" si applica alle chiavi di un dict.)

Altre risposte ti hanno già dato il codice, spero che questo dia un po 'di intuizione. Spero che Alex Martelli risponderà con ancora più dettagli.


4

Vuoi aggiungere una tupla, non un elenco:

>>> a=set('abcde')
>>> a
set(['a', 'c', 'b', 'e', 'd'])
>>> l=['f','g']
>>> l
['f', 'g']
>>> t = tuple(l)
>>> t
('f', 'g')
>>> a.add(t)
>>> a
set(['a', 'c', 'b', 'e', 'd', ('f', 'g')])

Se hai un elenco, puoi convertirlo in tupla, come mostrato sopra. Una tupla è immutabile, quindi può essere aggiunta al set.


4

Ho scoperto che dovevo fare qualcosa di simile oggi. L'algoritmo sapeva quando stava creando un nuovo elenco che doveva essere aggiunto all'insieme, ma non quando avrebbe finito di operare nell'elenco.

Ad ogni modo, il comportamento che volevo era che set usasse idpiuttosto che hash. Come tale ho trovato mydict[id(mylist)] = mylistinvece di myset.add(mylist)offrire il comportamento che volevo.


3

Ti consigliamo di utilizzare le tuple, che sono hash (non puoi hash un oggetto mutevole come un elenco).

>>> a = set("abcde")
>>> a
set(['a', 'c', 'b', 'e', 'd'])
>>> t = ('f', 'g')
>>> a.add(t)
>>> a
set(['a', 'c', 'b', 'e', 'd', ('f', 'g')])

2

Ecco come lo faccio di solito:

def add_list_to_set(my_list, my_set):
    [my_set.add(each) for each in my_list]
return my_set

-4

Questo dovrebbe fare:

set(tuple(i) for i in L)
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.