Ian Mackinnon
Cuál es el “una […] manera obvia” para agregar todos los elementos de un iterable a uno existente set
?
Eliminación de negación única
Puede agregar elementos de un list
a un set
como esto:
>>> foo = set(range(0, 4))
>>> foo
set([0, 1, 2, 3])
>>> foo.update(range(2, 6))
>>> foo
set([0, 1, 2, 3, 4, 5])
-
Acabo de mirar hacia atrás en mi sesión de interpretación y en realidad probé esto, pero pensé que había agregado la lista completa como un elemento del conjunto debido a los corchetes en la representación del conjunto. Nunca antes me había dado cuenta de que están representados así.
–Ian Mackinnon
28 de octubre de 2010 a las 17:33
-
Esa representación le permite volver a pegarla en una sesión interactiva, porque el
set
constructor toma un iterable como su argumento.– Frank Kusters
5 de abril de 2013 a las 7:02
-
Tenga en cuenta que la representación es sólo por ejemplo
{1, 2, 3}
en Python 3 mientras que eraset([1, 2, 3])
en Phyton 2.– Radón Rosborough
26 de noviembre de 2017 a las 0:04
Juan maquin
Para el beneficio de cualquiera que pudiera creer, por ejemplo, que hacer aset.add()
en un bucle tendría un rendimiento competitivo con hacer aset.update()
aquí hay un ejemplo de cómo puede probar sus creencias rápidamente antes de hacerlo 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 el costo por elemento del enfoque de bucle es TRES veces mayor que el del update
Acercarse.
Usando |= set()
cuesta alrededor de 1.5x lo que update
hace solo la mitad de lo que hace agregar cada elemento individual en un bucle.
Puede usar la función set() para convertir un iterable en un conjunto, y luego usar el operador de actualización de conjunto estándar (|=) para agregar los valores únicos de su nuevo conjunto al existente.
>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])
-
Usando
.update
tiene el beneficio de que el argumento puede ser iterable —no necesariamente un conjunto— a diferencia del RHS del|=
operador en su ejemplo.– tzot
28/10/2010 a las 21:31
-
Buen punto. Es solo una elección estética ya que set() puede convertir un iterable en un conjunto, pero la cantidad de pulsaciones de teclas es la misma.
– GBC
28 de octubre de 2010 a las 23:22
-
Nunca antes había visto ese operador, disfrutaré usarlo cuando aparezca en el futuro; ¡Gracias!
– eipxen
1 de agosto de 2011 a las 20:02
-
@eipxen: Hay
|
para unión,&
para la intersección, y^
para obtener elementos que están en uno u otro pero no en ambos. Pero en un lenguaje de escritura dinámica donde a veces es difícil leer el código y conocer los tipos de objetos que vuelan, dudo en usar estos operadores. Alguien que no los reconozca (o quizás ni siquiera se dé cuenta de que Python permite operadores como estos) podría confundirse y pensar que se están realizando algunas operaciones lógicas o bit a bit extrañas. Sería bueno si estos operadores también trabajaran en otros iterables…– El arte de la guerra
30/03/2015 a las 19:00
-
Realicé algunas pruebas de tiempo en este versus
.update()
y agregue elementos individuales en un bucle. Encontrado que.update()
fue más rápido Agregué mis resultados a esta respuesta existente: stackoverflow.com/a/4046249/901641– El arte de la guerra
30 de marzo de 2015 a las 19:39
Solo una actualización rápida, tiempos 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)
los resultados son:
one_by_one 10.184448844986036
cast_to_list_and_back 7.969255169969983
update_set 2.212590195937082
pifunc
Usa la comprensión de listas.
Cortocircuitando la creación de iterable usando una lista, por ejemplo 🙂
>>> 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])
>>>
[Edit: missed the set part of question]
-
¿No veo ningún conjunto? ¿Me estoy perdiendo de algo?
–Ian Mackinnon
28/10/2010 a las 17:25
Juan maquin
for item in items:
extant_set.add(item)
Para que conste, creo que la afirmación de que “debería haber una, y preferiblemente solo una, forma obvia de hacerlo”. es falso Hace una suposición que hacen muchas personas con mentalidad técnica, que todos piensan igual. Lo que es obvio para una persona no lo es tanto para otra.
Yo diría que mi solución propuesta es claramente legible y hace lo que usted pide. No creo que haya problemas de rendimiento involucrados, aunque admito que podría estar perdiéndome algo. Pero a pesar de todo eso, puede que no sea obvio y preferible a otro desarrollador.
-
¿No veo ningún conjunto? ¿Me estoy perdiendo de algo?
–Ian Mackinnon
28/10/2010 a las 17:25