Python- ¿Cómo generar enteros aleatorios con múltiples rangos?

Me he encontrado confuso al generar X cantidad de enteros aleatorios de diferentes conjuntos de (a, b). Por ejemplo, me gustaría generar 5 enteros aleatorios que provienen de (1,5), (9,15) y (21,27). Mi código genera 5 enteros aleatorios, pero solo entre 21 y 27 y no a partir de los otros dos. Idealmente, me gustaría ver algo como 1,4,13,22,25 en lugar de 21,21,25,24,27.

Mi código:

from random import randint n = 0 while n < 5: n += 1 for i in (randint(1,5),randint(9,15),randint(21,27)): x = i print i 

No es ideal

 from random import randint, choice for _ in range(5): print(choice([randint(1,5),randint(9,15),randint(21,27)])) 

Como dijo Blender – versión más clara

 from random import randint, choice for _ in range(5): r = choice([(1,5),(9,15),(21,27)]) print(randint(*r)) 

¡Hola!

Esta es una pregunta interesante; se vuelve interesante cuando te das cuenta de que para lograr una verdadera aleatoriedad, la probabilidad de elegir un rango particular debe ser ponderada por la longitud de ese rango.

Rangos de igual longitud:

Si los tres rangos son de igual longitud, digamos rango (0, 10), rango (20, 30) y rango (40, 50); luego, para elegir un solo número aleatorio, podemos hacer lo siguiente:

  1. Elige un rango al azar.
  2. Elija un número al azar de ese rango.

Rangos de longitud desigual:

Ahora, considere tres de rangos de tamaño desigual, digamos rango (0, 2), rango (4, 6) y rango (10, 100);

El tercer rango es mucho más grande que los dos primeros. Si empleamos la misma estrategia que empleamos para lidiar con rangos igualmente largos, estaremos predispuestos a elegir números de los dos primeros rangos.

Para elegir números verdaderamente aleatorios de los tres rangos desigualmente largos, hay dos estrategias.

Estrategia 1: Uso de probabilidad

La probabilidad de elegir un rango debe ser tal que la probabilidad de elegir un número siga siendo la misma. Podríamos lograr esto sopesando la probabilidad de piking rangos más cortos.

Sin embargo, en lugar de calcular los pesos de probabilidad; Hay una mejor solución. Ver Estrategia 2.

Estrategia 2: Fusionar los rangos.

Simplemente podríamos fusionar los tres rangos en un solo rango. Luego, elige aleatoriamente un número del rango combinado. Es sencillo:

 import random; def randomPicker(howMany, *ranges): mergedRange = reduce(lambda a, b: a + b, ranges); ans = []; for i in range(howMany): ans.append(random.choice(mergedRange)); return ans; 

Vamos a verlo en acción:

 >>> randomPicker(5, range(0, 10), range(15, 20), range(40, 60)); [47, 50, 4, 50, 16] >>> randomPicker(5, range(0, 10), range(70, 90), range(40, 60)); [0, 9, 55, 46, 44] >>> randomPicker(5, range(0, 10), range(40, 60)); [50, 43, 7, 42, 4] >>> 

Un beneficio adicional de randomPicker es que puede lidiar con cualquier número de rangos.

Espero que esto ayude.

 for i in (randint(1,5),randint(9,15),randint(21,27)): print i 

Este bucle de suelo generará 3 números aleatorios, uno desde el primer rango suministrado, otro para el segundo rango y el último para el último rango, e imprime cada uno en la salida. Su impresión está fuera del bucle de foor e imprime solo el último número aleatorio del último rango dado.

para números no repetidos:

 from random import randint, choice randoms = [] counter = 0 while True: new_random = (choice([randint(1,5),randint(9,15),randint(21,27)])) if new_random not in randoms: randoms.append(new_random) counter += 1 if counter == 5 : break print randoms 

Hay algunas respuestas interesantes aquí, aunque creo que este problema se puede resolver con un poco menos de código, incluso si es un poco menos legible.

La idea básica aquí es que tiene un número fijo de opciones por lo que esencialmente puede tener un rango para hacer el trabajo y luego trazar el resultado a los rangos que desea. O si quieres considerarlo de otra manera, crea una función f(x) -> y que se reduzca a lo mismo.

 from random import randint for i in xrange(5): n = randint(1,19) if n > 12: print(n + 8) elif n > 5: print(n + 3) else: print(n) 

O bien, con una función:

 from random import randint def plot_to_ranges(n): if n > 12: return n + 8 elif n > 5: return n + 3 else: return n for i in xrange(5): n = randint(1,19) print(plot_to_ranges(n)) 

Si está utilizando Python 3.x, debe cambiar xrange a range .