¿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])

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.


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])

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

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]


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.


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.