Qual é a "única maneira [...] óbvia" de adicionar todos os itens de um iterável a um existente set
?
Qual é a "única maneira [...] óbvia" de adicionar todos os itens de um iterável a um existente set
?
Respostas:
Você pode adicionar elementos de list
a set
como este:
>>> foo = set(range(0, 4))
>>> foo
set([0, 1, 2, 3])
>>> foo.update(range(2, 6))
>>> foo
set([0, 1, 2, 3, 4, 5])
set
construtor assume uma iterável como argumento.
{1, 2, 3}
em Python 3 enquanto era set([1, 2, 3])
em Python 2.
Para o benefício de qualquer um que possa acreditar, por exemplo, que fazer aset.add()
em loop teria desempenho competitivo em relação a fazer aset.update()
, aqui está um exemplo de como você pode testar suas crenças rapidamente antes de se tornar público:
>\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
Parece que o custo por item da abordagem de loop é mais de TRÊS vezes o da update
abordagem.
Usar |= set()
custos cerca de 1,5x o que update
faz, mas metade do que adiciona cada item individual em um loop.
Você pode usar a função set () para converter um iterável em um conjunto e, em seguida, usar o operador de atualização de conjunto padrão (| =) para adicionar os valores exclusivos do seu novo conjunto ao existente.
>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])
.update
tem o benefício de que o argumento pode ser iterável - não necessariamente um conjunto - ao contrário do RHS do |=
operador em seu exemplo.
|
união, &
interseção e ^
obtenção de elementos que estão em um ou no outro, mas não em ambos. Mas em uma linguagem de tipo dinâmico, onde às vezes é difícil ler o código e conhecer os tipos de objetos voando, sinto-me hesitante em usar esses operadores. Alguém que não os reconhece (ou talvez nem perceba que o Python permite operadores como esses) pode ficar confuso e pensar que algumas operações lógicas ou bit a bit estão acontecendo. Seria bom se esses operadores também trabalhassem em outros
.update()
e adicione elementos individuais em um loop. Achei que .update()
era mais rápido. Adicionei meus resultados a esta resposta existente: stackoverflow.com/a/4046249/901641
Apenas uma atualização rápida, horários 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)
Os resultados são:
one_by_one 10.184448844986036
cast_to_list_and_back 7.969255169969983
update_set 2.212590195937082
Use a compreensão da lista.
Curto-circuito na criação de iterável usando uma lista, por exemplo :)
>>> 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])
>>>
[Editar: perdeu a parte definida da pergunta]
for item in items:
extant_set.add(item)
Para o registro, acho que a afirmação de que "deveria haver uma - e de preferência apenas uma - maneira óbvia de fazê-lo". é falso. Supõe-se que muitas pessoas de espírito técnico fazem, que todo mundo pensa da mesma forma. O que é óbvio para uma pessoa não é tão óbvio para outra.
Eu diria que minha solução proposta é claramente legível e faz o que você pede. Não acredito que haja algum impacto no desempenho envolvido - embora admita que possa estar faltando alguma coisa. Mas, apesar de tudo isso, pode não ser óbvio e preferível a outro desenvolvedor.
aset.update(iterable)
loop na velocidade C e o for item in iterable: aset.add(item)
loop na velocidade do Python, com uma pesquisa de método e uma chamada de método (aarrgghh !!) por item.