¿Puede Python generar un número aleatorio que excluya un conjunto de números, sin usar recursión?

Miré los documentos de Python (es posible que haya entendido mal), pero no vi que hubiera una forma de hacerlo (ver más abajo) sin llamar a una función recursiva.
Lo que me gustaría hacer es generar un valor aleatorio que excluya los valores en el medio.

En otras palabras,
Imaginemos que quería que X fuera un número aleatorio que no está en
range(a - b, a + b)
¿Puedo hacer esto en el primer paso,
o
1. ¿Tengo que generar constantemente un número,
2. Comprobar si en el range() ,
3. Lavar enjuague?

En cuanto a por qué no deseo escribir una función recursiva,
1. ‘se siente como’ no debería tener que
2. El conjunto de números para los que estoy haciendo esto podría terminar siendo bastante grande, y
… Escuché que los desbordamientos de stack son malos, y podría ser demasiado cauteloso al hacer esto.

Estoy seguro de que hay una manera agradable, Pythonic, no recursiva de hacerlo.

Utilice random.choice (). En este ejemplo, a es su límite inferior, el rango entre byc se omite yd es su límite superior.

 import random numbers = range(a,b) + range(c,d) r = random.choice(numbers) 

Genere un número aleatorio y mapéelo en los rangos de números que desee.

Si quisiera generar un número entero entre 1-4 o 7-10 , excluyendo 5 y 6 , podría:

  1. Generar un entero aleatorio en el rango 1-8
  2. Si el número aleatorio es mayor que 4, agregue 2 al resultado.

El mapeo se convierte en:

 Random number: 1 2 3 4 5 6 7 8 Result: 1 2 3 4 7 8 9 10 

Haciéndolo de esta manera, nunca necesitas “volver a tirar”. El ejemplo anterior es para enteros, pero también se puede aplicar a flotadores.

Una posible solución sería simplemente cambiar los números aleatorios fuera de ese rango. P.ej

 def NormalWORange(a, b, sigma): r = random.normalvariate(a,sigma) if r < a: return rb else: return r+b 

Eso generaría una distribución normal con un agujero en el rango (ab, a + b).

Edición: si quieres enteros, necesitarás un poco más de trabajo. Si desea números enteros que estén en el rango [c, ab] o [a + b, d], lo siguiente debe hacer el truco.

 def RangeWORange(a, b, c, d): r = random.randrange(c,d-2*b) # 2*b because two intervals of length b to exclude if r >= ab: return r+2*b else: return r 

Puede que haya entendido mal su problema, pero puede implementar esto sin recursión

 def rand(exclude): r = None while r in exclude or r is None: r = random.randrange(1,10) return r rand([1,3,9]) 

sin embargo, todavía estás repasando los resultados hasta que encuentres nuevos.

La solución más rápida sería esta (con a y b que definen la zona de exclusión y c y d el conjunto de buenas respuestas, incluida la zona de exclusión):

 offset = b - a maximum = d - offset result = random.randrange(c, maximum) if result >= a: result += offset 

Aún necesita cierto rango, es decir, un valor mínimo-máximo posible, excluyendo sus valores medios.

¿Por qué no elige aleatoriamente la “mitad” del rango que desea, y luego elige un número aleatorio en ese rango? P.ej:

 def rand_not_in_range(a,b): rangechoices = ((0,ab-1),(a+b+1, 10000000)) # Pick a half fromrange = random.choice(rangechoices) # return int from that range return random.randint(*fromrange) 

La respuesta de Li-aung Yip hace que el tema de la recursión sea discutible, pero debo señalar que es posible hacer cualquier grado de recursión sin preocuparme por la stack. Se llama “recursión de cola”. Python no admite la recursión de la cola directamente, porque GvR cree que no está bien:

http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html

Pero puedes sortear esto:

http://paulbutler.org/archives/tail-recursion-in-python/

Me parece interesante que Stick piense que la recursión “se siente mal”. En lenguajes extremadamente orientados a la función, como el Esquema, la recursión es inevitable. Le permite hacer iteraciones sin crear variables de estado, que el paradigma de progtwigción funcional evita rigurosamente.

http://www.pling.org.uk/cs/pop.html