Digamos que tengo una lista x
con una longitud desconocida de la que quiero sacar aleatoriamente un elemento para que la lista no contenga el elemento después. ¿Cuál es la forma más pitónica de hacer esto?
Puedo hacerlo usando un combincation en lugar de torpe pop
, random.randint
y len
, y me gustaría ver soluciones más cortos o más agradables:
import random
x = [1,2,3,4,5,6]
x.pop(random.randint(0,len(x)-1))
Lo que estoy tratando de lograr es sacar consecutivamente elementos aleatorios de una lista. (es decir, sacar aleatoriamente un elemento y moverlo a un diccionario, sacar aleatoriamente otro elemento y moverlo a otro diccionario, ...)
Tenga en cuenta que estoy usando Python 2.6 y no encontré ninguna solución a través de la función de búsqueda.
Respuestas:
Lo que parece estar haciendo no parece muy Pythonic en primer lugar. No debe eliminar cosas del medio de una lista, porque las listas se implementan como matrices en todas las implementaciones de Python que conozco, por lo que esta es una
O(n)
operación.Si realmente necesita esta funcionalidad como parte de un algoritmo, debe verificar una estructura de datos como la
blist
que admite la eliminación eficiente desde el medio.En Python puro, lo que puede hacer si no necesita acceso a los elementos restantes es simplemente barajar la lista primero y luego iterar sobre ella:
lst = [1,2,3] random.shuffle(lst) for x in lst: # ...
Si realmente necesita el resto (que es un poco a código, en mi humilde opinión), al menos puede hacerlo
pop()
desde el final de la lista ahora (¡que es rápido!):while lst: x = lst.pop() # do something with the element
En general, a menudo puede expresar sus programas de manera más elegante si usa un estilo más funcional, en lugar de un estado mutante (como lo hace con la lista).
fuente
random.shuffle(x)
y luegox.pop()
? ¿No entiendo cómo hacer esto "funcional"?zip
obtener una lista de pares (dict, number). Dijiste algo sobre varios diccionarios de los cuales quieres asociar cada uno con un número aleatorio.zip
es perfecto para estoNo será mucho mejor que eso, pero aquí hay una ligera mejora:
Documentación sobre
random.randrange()
:fuente
Para eliminar un solo elemento en un índice aleatorio de una lista si el orden del resto de los elementos de la lista no importa:
import random L = [1,2,3,4,5,6] i = random.randrange(len(L)) # get random index L[i], L[-1] = L[-1], L[i] # swap with the last element x = L.pop() # pop last element O(1)
El intercambio se utiliza para evitar el comportamiento de O (n) al eliminarlo de la mitad de una lista.
fuente
Aquí hay otra alternativa: ¿por qué no baraja la lista primero y luego comienza a mostrar elementos hasta que no queden más elementos? Me gusta esto:
import random x = [1,2,3,4,5,6] random.shuffle(x) while x: p = x.pop() # do your stuff with p
fuente
[for p in x]
Una forma de hacerlo es:
fuente
pop
puede apuntar un nombre al elemento eliminado, con esto no puede.remove
requiere un escaneo lineal de la lista. Eso es terriblemente ineficiente en comparación con buscar un índice.Si bien no salgo de la lista, encontré esta pregunta en Google al intentar obtener X elementos aleatorios de una lista sin duplicados. Esto es lo que finalmente usé:
items = [1, 2, 3, 4, 5] items_needed = 2 from random import shuffle shuffle(items) for item in items[:items_needed]: print(item)
Esto puede ser un poco ineficaz ya que está barajando una lista completa pero solo usa una pequeña parte de ella, pero no soy un experto en optimización, por lo que podría estar equivocado.
fuente
random.sample(items, items_needed)
Sé que esta es una pregunta antigua, pero solo por el bien de la documentación:
Si usted (la persona que busca en Google la misma pregunta) está haciendo lo que creo que está haciendo, que es seleccionar k número de elementos al azar de una lista (donde k <= len (su lista)), pero asegurándose de que cada elemento nunca se seleccione más de una vez (= muestreo sin reemplazo), puede usar random.sample como sugiere @ jf-sebastian. Pero sin saber más sobre el caso de uso, no sé si esto es lo que necesita.
fuente
Esta respuesta es cortesía de @ niklas-b :
" Probablemente quieras usar algo como pypi.python.org/pypi/blist "
Para citar la página de PYPI :
Se supondría un rendimiento reducido en el extremo de ejecución aleatoria / acceso aleatorio , ya que es una estructura de datos de "copia en escritura". Esto viola muchos supuestos de casos de uso en las listas de Python, así que úselo con cuidado .
SIN EMBARGO, si su caso de uso principal es hacer algo extraño y antinatural con una lista (como en el ejemplo forzado dado por @OP, o mi problema Python 2.6 FIFO queue-with-pass-over), entonces esto encajará muy bien .
fuente
a pesar de muchas respuestas que sugieren su uso
random.shuffle(x)
yx.pop()
es muy lento en datos grandes. y el tiempo requerido en una lista de10000
elementos que tomó6 seconds
cuando se habilitó la reproducción aleatoria. cuando la reproducción aleatoria está desactivada, la velocidad0.2s
el método más rápido después de probar todos los métodos dados anteriormente resultó ser escrito por @jfs
import random L = ['1',2,3,'4'...1000] #you can take mixed or pure list i = random.randrange(len(L)) # get random index L[i], L[-1] = L[-1], L[i] # swap with the last element x = L.pop() # pop last element O(1)
en apoyo de mi afirmación, aquí está el gráfico de complejidad de tiempo de esta fuente
SI no hay duplicados en la lista,
también puede lograr su propósito usando conjuntos. una vez que la lista se haya convertido en un conjunto de duplicados, se eliminarán.
remove by value
yremove random
costoO(1)
, es decir, muy eficiente. Este es el método más limpio que se me ocurrió.L=set([1,2,3,4,5,6...]) #directly input the list to inbuilt function set() while 1: r=L.pop() #do something with r , r is random element of initial list L.
A diferencia de
lists
quéA+B
opción de soporte ,sets
también admiteA-B (A minus B)
junto conA+B (A union B)
yA.intersection(B,C,D)
. super útil cuando desea realizar operaciones lógicas en los datos.OPCIONAL
SI desea velocidad cuando las operaciones se realizan en la cabeza y la cola de la lista, use python dequeue (cola de dos extremos) en apoyo de mi afirmación, aquí está la imagen. una imagen son mil palabras.
fuente