¿Cómo agrego el contenido de un iterable a un conjunto?

Respuestas:

228

Puede agregar elementos de lista a setcomo 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])
SingleNegationElimination
fuente
2
Solo volví a mirar mi sesión de intérprete y en realidad lo intenté, 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
77
Esa representación le permite pegarla nuevamente en una sesión interactiva, porque el setconstructor toma un iterable como argumento.
Frank Kusters
3
Tenga en cuenta que la representación es solo, por ejemplo, {1, 2, 3}en Python 3, mientras que estaba set([1, 2, 3])en Python 2.
Radon Rosborough
40

Para el beneficio de cualquier persona que pueda creer, por ejemplo, que hacer aset.add()un ciclo tendría un rendimiento competitivo aset.update(), aquí hay un ejemplo de cómo puede poner a prueba 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 artículo del enfoque de bucle es TRES veces mayor que el del updateenfoque.

El uso |= set()cuesta aproximadamente 1.5 updateveces lo que hace, pero la mitad de lo que hace agregar cada elemento individual en un ciclo.

John Machin
fuente
14

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])
gbc
fuente
55
El uso .updatetiene el beneficio de que el argumento puede ser iterable, no necesariamente un conjunto, a diferencia del RHS del |=operador en su ejemplo.
tzot
1
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
Nunca antes había visto ese operador, disfrutaré usándolo cuando aparezca en el futuro; ¡Gracias!
eipxen
1
@eipxen: Hay |para unión, &intersección y ^para obtener elementos que están en uno u otro pero no en ambos. Pero en un lenguaje de tipo dinámico donde a veces es difícil leer el código y conocer los tipos de objetos que vuelan, me siento reacio a usar estos operadores. Alguien que no los reconoce (o tal vez ni siquiera se da cuenta de que Python permite operadores como estos) podría confundirse y pensar que están ocurriendo algunas operaciones lógicas o bit a bit extrañas. Sería bueno si estos operadores trabajaran también en otros iterables ...
ArtOfWarfare
Ejecuté algunas pruebas de tiempo en este versus .update()y agregué elementos individuales en un bucle. Descubrí que .update()fue más rápido.
Agregué
4

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
Daniel Dubovski
fuente
0

Usa la comprensión de la lista.

Cortocircuito en la creación de iterables 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])
>>> 

[Editar: se perdió la parte de la pregunta establecida]

pyfunc
fuente
1
No veo ningún set? ¿Me estoy perdiendo de algo?
Ian Mackinnon
-2
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 Supone que muchas personas de mentalidad técnica hacen, que todos piensan igual. Lo que es obvio para una persona no es tan obvio para otra.

Yo diría que mi solución propuesta es claramente legible y hace lo que usted pide. No creo que haya ningún éxito en el rendimiento involucrado, aunque admito que podría estar perdiendo algo. Pero a pesar de todo eso, puede que no sea obvio y preferible para otro desarrollador.

jaydel
fuente
Argh! El bucle for que se encuentra en una línea como esa se formatea en mi respuesta; nunca haría eso. Nunca.
Jaydel
Tienes toda la razón. Edité la publicación para reparar mi daño. Gracias :)
Jaydel
9
Te estás perdiendo el punto que se aset.update(iterable)repite a velocidad C, mientras que se for item in iterable: aset.add(item)repite a velocidad de Python, con una búsqueda de método y una llamada de método (¡¡¡aarrgghh !!) por elemento.
John Machin
1
Lo siento, no dijo nada sobre el rendimiento en su pregunta, así que no me preocupé por eso.
jaydel