Adicionar lista ao conjunto?

242

Testado no interpretador 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

Eu acho que não posso adicionar a lista ao conjunto porque não há como o Python saber se eu adicionei a mesma lista duas vezes. Existe uma solução alternativa?

EDIT: Eu quero adicionar a lista em si, não seus elementos.

Adam Matan
fonte
2
Deseja adicionar a lista ao conjunto ou aos itens da lista?
pkit 20/08/09
A lista em si - eu quero ter um conjunto de listas.
21820 Adam Matan
Parece que a resposta mais adequada é a menosprezada, sugerindo o uso de aSet.add (id (lst)) antes de adicionar o próprio lst a alguma lista / fila / etc, para garantir que você fez isso. Você deve reconsiderar a resposta aceita.
Rustam A.

Respostas:

187

Você não pode adicionar uma lista a um conjunto porque as listas são mutáveis, o que significa que você pode alterar o conteúdo da lista depois de adicioná-lo ao conjunto.

No entanto, você pode adicionar tuplas ao conjunto, porque não é possível alterar o conteúdo de uma tupla:

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

Edit : alguma explicação: A documentação define a setcomo uma coleção não ordenada de objetos hash distintos. Os objetos devem ser laváveis ​​para que a localização, adição e remoção de elementos possa ser feita mais rapidamente do que observar cada elemento individual toda vez que você executar essas operações. Os algoritmos específicos usados ​​são explicados no artigo da Wikipedia . Os algoritmos de hash do Pythons são explicados no effbot.org e o pythons __hash__funciona na referência do python .

Alguns fatos:

  • Os elementos do conjunto e as teclas do dicionário precisam ser laváveis
  • Alguns tipos de dados unhashable:
    • list: use em tuplevez disso
    • set: use em frozensetvez disso
    • dict: não tem contrapartida oficial, mas existem algumas receitas
  • As instâncias de objeto são hashable por padrão, com cada instância tendo um hash exclusivo. Você pode substituir esse comportamento, conforme explicado na referência python.
Otto Allmendinger
fonte
6
E se você quiser adicionar um conjunto a um conjunto, use frozenset.
FogleBird 20/08/09
4
collections.namedtuplepode ser considerado equivalente "oficial" do dict.
SilentGhost 20/08/09
1
@ Wahnfrieden: que está adicionando o conteúdo de um conjunto, não o próprio conjunto.
Otto Allmendinger
@aehlke: Não, isso adiciona os elementos do conjunto ao primeiro conjunto, mas estamos falando de adicionar um conjunto como um elemento do primeiro conjunto.
Jeff Learman
578

Use set.update()ou|=

>>> 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'}

editar: se você deseja adicionar a lista em si e não seus membros, infelizmente deve usar uma tupla. Os membros do conjunto devem ser laváveis .

aehlke
fonte
set.update () adiciona a lista ao conjunto, correto? para que serve o operador de pipe igual?
FistOfFury 7/01
Com relação aos conjuntos, o |operador implementa a operação de união do conjunto . Tanto o |=operador quanto o set.update()método aplicam essa operação no local e são efetivamente sinônimos. Portanto, set_a |= set_bpoderia ser considerado açúcar sintático para ambos set_a.update(set_b) e set_a = set_a | set_b (exceto que, no último caso, o mesmo set_aobjeto é reutilizado em vez de reatribuído). </ahem>
Cecil Curry
76

Para adicionar os elementos de uma lista a um conjunto , useupdate

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

s.update (t): retorna set s com elementos adicionados de t

Por exemplo

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

Se você deseja adicionar a lista inteira como um único elemento ao conjunto, não pode, porque as listas não são hasháveis. Você poderia adicionar uma tupla, por exemplo s.add(tuple(l)). Consulte também TypeError: unhashable type: 'list' ao usar a função de conjunto embutida para obter mais informações sobre isso.

JDiMatteo
fonte
40

Espero que isso ajude:

>>> 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'])
alvas
fonte
15

Por favor, observe a função set.update(). A documentação diz:

Atualize um conjunto com a união de si e de outros.

eggfly
fonte
5
Isso não responder à pergunta (uma vez que o OP quer adicionar a própria lista para o conjunto) mas foi a resposta que eu precisava quando o Google trouxe-me aqui :-)
tom Stratton
1
Bem, parece a resposta mais relevante para a pergunta para mim ... por exemplo, se b = set ([1]), b.update ([7,25]) fornecerá a b o seguinte valor: set ([ 1, 25, 7]) ---> Não é o que estamos procurando aqui?
Louis LC
8

Os objetos da lista são removíveis . você pode querer transformá-los em tuplas.

SilentGhost
fonte
5

Os conjuntos não podem ter elementos / membros mutáveis ​​(alteráveis). Uma lista, sendo mutável, não pode ser membro de um conjunto.

Como os conjuntos são mutáveis, você não pode ter um conjunto de conjuntos! Você pode ter um conjunto de frozensets.

(O mesmo tipo de "requisito de mutabilidade" se aplica às chaves de um ditado.)

Outras respostas já lhe deram código, espero que isso dê um pouco de insight. Espero que Alex Martelli responda com ainda mais detalhes.

user135331
fonte
4

Você deseja adicionar uma tupla, não uma lista:

>>> 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 você tiver uma lista, poderá converter para a tupla, como mostrado acima. Uma tupla é imutável, portanto pode ser adicionada ao conjunto.

hughdbrown
fonte
4

Descobri que precisava fazer algo semelhante hoje. O algoritmo sabia quando estava criando uma nova lista que precisava ser adicionada ao conjunto, mas não quando teria terminado de operar na lista.

De qualquer forma, o comportamento que eu queria era usar ide não usar hash. Como tal, encontrei em mydict[id(mylist)] = mylistvez de myset.add(mylist)oferecer o comportamento que queria.

Dunas
fonte
3

Você desejará usar tuplas, que podem ser lavadas (você não pode misturar um objeto mutável como uma lista).

>>> 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')])
Noé
fonte
2

Aqui está como eu costumo fazer isso:

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

Isso deve fazer:

set(tuple(i) for i in L)
WQS
fonte