2012-05-19 30 views
26

Miré más de Python Docs (puedo haber entendido mal), pero no vi que hubiera una manera de hacer esto (mira debajo) sin llamar a una función recursiva.
Lo que me gustaría hacer es generar un valor aleatorio que excluya valores en el medio.¿Puede Python generar un número aleatorio que excluya un conjunto de números, sin usar la recursión?

En otras palabras,
Imaginemos que quería X ser un número aleatorio que no está en
range(a - b, a + b)
¿Puedo hacer esto en la primera pasada,
o
1. ¿Tengo que generar constantemente un número,
2. Marque si en range(),
3. Lave el enjuague?

cuanto a por qué no deseo escribir una función recursiva,
1. 'se siente como' Yo no debería tener que
2. El conjunto de números que estoy haciendo esto para en realidad podría terminar siendo bastante grande, y
... He oído que los desbordamientos de pila son malos, y podría ser demasiado cauteloso al hacer esto.

Estoy seguro de que hay una manera agradable, no pittónica, recursiva de hacerlo.

Respuesta

25

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

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

Esto funcionará a menos que el conjunto de respuestas posibles sea extremadamente grande, en cuyo caso usará demasiada memoria y se bloqueará. –

+0

@AndrewG: De acuerdo, no es ideal si tiene un rango de millones/billones. Por otro lado, es simple y memorable. Su respuesta, si bien es una solución muy buena y robusta, podría ser más propensa a errores. – Junuxx

+1

Sí. Usaría tu respuesta si a, b, cyd se conocían desde el principio y se sabía que era un conjunto pequeño, y el mío si dependían de una entrada o si se sabía que era un conjunto grande. –

4

la solución más rápida sería este (con a y b que define la zona de exclusión y C y D el conjunto de buenas respuestas, incluyendo la zona de exclusión):

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

Hmm, tiene que haber un error lógico en la última sección de código - tratando de depurar ahora –

+0

... oh. debería ser offset = b - a. Edición. –

+0

Y también debería ser resultado> = a. Ahí, eso debería hacerlo. –

6

que puede haber entendido mal su problema, pero se puede aplicar esto sin recursividad

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

rand([1,3,9]) 

embargo, usted todavía está en bucle sobre los resultados hasta que encuentre nuevos.

0

Aún necesita un rango de, es decir, un valor posible min-max que excluye los valores medios.

¿Por qué no elige al azar la "mitad" del rango que desea, y luego elige un número al azar en ese rango? P. ej .:

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

Esto obtendrá una distribución 50/50 entre los dos rangos, independientemente de cuán grandes sean entre sí. –

9

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

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

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

Editar: Si quieres enteros entonces necesitarás un poco más de trabajo. Si quiere enteros que están en el rango [c, a-b] o [a + b, d], lo siguiente debería ser 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 >= a-b: 
     return r+2*b 
    else: 
     return r 
40

Genere un número aleatorio y asócielo en los rangos de números que desee.

Si desea generar un entero entre 1-4 o 7-10, excluyendo 5 y 6, es posible que:

  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 

Hacerlo de esta manera, que no será necesario "re-roll". El ejemplo anterior es para enteros, pero también se puede aplicar a flotantes.

+0

+1 para una buena explicación: esto es a lo que me refería, pero no me resultó claro explicarlo con solo el código. –

+3

@AndrewG. : Gracias. :) Se podría explicar aún mejor con algunas fotos, pero la energía de activación para mí al abrir Visio es un poco alta esta noche. ;) –

+0

Muchas gracias por esto, es muy sencillo en su ejecución e inspira al lector a dibujar la respuesta obvia en lugar de simplemente publicar el código y decir: "Aquí, ejecute esto". Al final fui con la solución de Junuxx, pero aprecio la elegancia de esta respuesta también. –

0

Li-aung La respuesta de Yip hace que la cuestión de la recursión sea discutible, pero debo señalar que es posible hacer cualquier grado de recursión sin preocuparse por la pila. Se llama "recursividad de cola". Python no soporta la recursión de cola directamente, ya RGv piensa que es cool:

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

Pero usted puede evitar esto:

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

Me parece interesante que se pegan piensa que la recursividad " se siente mal ". En lenguajes extremadamente orientados a funciones, como Scheme, la recursividad es inevitable. Le permite realizar iteraciones sin crear variables de estado, que el paradigma de programación funcional evita rigurosamente.

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

+0

Como alguien nuevo en la programación, esto es totalmente lo que necesito leer. ¡Gracias!No soy necesariamente alérgico a la recursión y, a decir verdad, no me di cuenta de que incluso el BDFL de Python mostraba desprecio por él en general; Simplemente tuve la sensación de que no necesitaba usarlo para este proyecto en particular. No lo descartaría en futuros esfuerzos. –

+0

Oye, si mi respuesta fue útil, ¡votala! Necesito la reputación. –

+0

Pensé que tenía. Mi error :) –

Cuestiones relacionadas