Can Python generate a random number that excludes a set of numbers, without using recursion?

前端 未结 7 1343
悲哀的现实
悲哀的现实 2020-12-30 20:46

I looked over Python Docs (I may have misunderstood), but I didn\'t see that there was a way to do this (look below) without calling a recursive function.
What I\'d like

相关标签:
7条回答
  • 2020-12-30 20:46

    You still need some range, i.e., a min-max possible value excluding your middle values.

    Why don't you first randomly pick which "half" of the range you want, then pick a random number in that range? E.g.:

    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)
    
    0 讨论(0)
  • 2020-12-30 20:52

    Li-aung Yip's answer makes the recursion issue moot, but I have to point out that it's possible to do any degree of recursion without worrying about the stack. It's called "tail recursion". Python doesn't support tail recursion directly, because GvR thinks it's uncool:

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

    But you can get around this:

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

    I find it interesting that stick thinks that recursion "feels wrong". In extremely function-oriented languages, such as Scheme, recursion is unavoidable. It allows you to do iteration without creating state variables, which the functional programming paradigm rigorously avoids.

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

    0 讨论(0)
  • 2020-12-30 20:58

    I may have misunderstood your problem, but you can implement this without recursion

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

    though, you're still looping over results until you find new ones.

    0 讨论(0)
  • 2020-12-30 21:06

    The fastest solution would be this (with a and b defining the exclusion zone and c and d the set of good answers including the exclusion zone):

    offset = b - a
    maximum = d - offset
    result = random.randrange(c, maximum)
    if result >= a:
        result += offset
    
    0 讨论(0)
  • 2020-12-30 21:07

    A possible solution would be to just shift the random numbers out of that range. E.g.

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

    That would generate a normal distribution with a hole in the range (a-b,a+b).

    Edit: If you want integers then you will need a little bit more work. If you want integers that are in the range [c,a-b] or [a+b,d] then the following should do the trick.

    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
    
    0 讨论(0)
  • 2020-12-30 21:10

    Use random.choice(). In this example, a is your lower bound, the range between b and c is skipped and d is your upper bound.

    import random
    numbers = range(a,b) + range(c,d)
    r = random.choice(numbers)
    
    0 讨论(0)
提交回复
热议问题