python - repetir - ¿Cuál es la forma más pitónica de sacar un elemento aleatorio de una lista?
llenar una matriz con numeros aleatorios en python (8)
Aquí hay otra alternativa: ¿por qué no barajas la lista primero y luego comienzas a hacer estallar 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
Digamos que tengo una lista x
con una longitud desconocida de la que quiero hacer pop 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?
Lo puedo hacer usando una combinación de pop
random.randint
, random.randint
, y len
y me gustaría ver soluciones más cortas o más random.randint
:
import random
x = [1,2,3,4,5,6]
x.pop(random.randint(0,len(x)-1))
Editar: Lo que estoy tratando de lograr son consecutivamente elementos aleatorios pop de una lista. (es decir, pop al azar un elemento y moverlo a un diccionario, pop 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.
Aunque no aparece en la lista, me encontré con esta pregunta en Google mientras trataba de obtener X elementos aleatorios de una lista sin duplicados. Esto es lo que finalmente utilicé:
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 ineficiente ya que está barajando una lista completa pero solo usando una pequeña porción de ella, pero no soy un experto en optimización, así que podría estar equivocado.
Esta respuesta es cortesía de :
" Probablemente quieras usar algo como pypi.python.org/pypi/blist "
Para citar la pypi.python.org/pypi/blist :
... un tipo de lista con un mejor rendimiento asintótico y un rendimiento similar en listas pequeñas
El blist es un reemplazo directo para la lista de Python que proporciona un mejor rendimiento cuando se modifican listas grandes. El paquete blist también proporciona sortedlist, sortedset, weaksortedlist, weaksortedset, sorteddict y btuple.
Uno supondría un rendimiento reducido en el extremo de acceso aleatorio / aleatorio , ya que es una estructura de datos de "copia en escritura". Esto viola muchas suposiciones de casos de uso en las listas de Python, por lo tanto , úselo con cuidado .
SIN EMBARGO, si su caso de uso principal es hacer algo raro y antinatural con una lista (como en el ejemplo forzado dado por @OP, o mi Python 2.6 FIFO queue-pass-over), entonces esto encajará bien .
Lo que parece que estás haciendo no parece muy Pythonic en primer lugar. No debe eliminar cosas de la mitad de una lista, porque las listas se implementan como matrices en todas las implementaciones de Python que conozco, por lo que esta es una operación O(n)
.
Si realmente necesita esta funcionalidad como parte de un algoritmo, debe verificar una estructura de datos como la lista que admita una eliminación eficiente desde el medio.
En Python puro, lo que puede hacer si no necesita acceder a los elementos restantes es simplemente mezclar la lista primero y luego repetirla:
lst = [1,2,3]
random.shuffle(lst)
for x in lst:
# ...
Si realmente necesita el resto (que es un poco olor a código, en mi humilde opinión), al menos puede 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 cambiar el estado (como lo hace con la lista).
No se encontrará mucho mejor que eso, pero aquí hay una leve mejoría:
x.pop(random.randrange(len(x)))
Documentación sobre random.randrange()
:
random.randrange ([inicio], stop [, paso])
Devuelve un elemento seleccionado al azar delrange(start, stop, step)
. Esto es equivalente a lachoice(range(start, stop, step))
, pero en realidad no construye un objeto rango.
Para eliminar un elemento individual al índice aleatorio de una lista si el orden del resto de los elementos de la lista no es importante:
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 usa para evitar el comportamiento O (n) al eliminarlo de la mitad de una lista.
Sé que esta es una vieja pregunta, pero solo por la documentación:
Si usted (la persona que busca la misma pregunta en Google) está haciendo lo que creo que está haciendo, que es seleccionar k números aleatoriamente de una lista (donde k <= len (lista)), pero asegurándose de que cada elemento nunca se seleccione más de una vez (= muestreo sin reemplazo), puede usar random.sample como random.sample @ jf-sebastian. Pero sin saber más sobre el caso de uso, no sé si esto es lo que necesita.
Una forma de hacerlo es:
x.remove(random.choice(x))