简体   繁体   中英

In python, how to generate a random integer in a range, excluding some numbers in a list?

For example, at beginning I want generate a random integer from (0,9),

at first time, the program generate 2, then I put 2 in the 'excluding' list,

next time, I need generate a number ranging between 0 to 9, and excluding 2. let's say it the second turn, the program generate 5.

The third turn, I need generate a number ranging from 0 to 9 and excluding 2 and 5.

As the range is very huge (million level), is there any method is efficient?

Generate the possible values once , shuffle that and pop values from that list each time:

values = range(10)
random.shuffle(values)

def get_value():
    return values.pop()

This will eventually produce all values in the range, in random order, without repetition.

As per the documentation for random.sample :

To choose a sample from a range of integers, use an xrange() object as an argument. This is especially fast and space efficient for sampling from a large population: sample(xrange(10000000), 60) .

This will sample without replacement, so random.sample(xrange(n), k) gives k different numbers in the range [0, n) (for k <= n ).

You could use function which maps integer range into same integer range with exceptions, like this:

import random

def excection(val, exceptions):
    ''' Maps range of values into
        similar range of values with exceptions missing.
        Exceptions must be sorted increasingly.

        for excample with exceptions=(2, 5) it will map
        This:       0, 1, 2, 3, 4, 5, 6
        To this:    0, 1, 3, 4, 6, 7, 8
    '''
    if not exceptions:
        return val

    for e in exceptions:
        if val < e: 
            return val # value before any exclusion is unchanged
        val += 1 # after some exclusion value is larger by one

    return val


def randint_with_exceptions(min, max, exceptions):
    r = random.randint(min, max - len(exceptions)) # generate random number in range smaller then desired by number of exceptions
    return excection(r, exceptions) # and map it to desired, more sparse sequence

for i in range(20): # test possible randoms
    print randint_with_exceptions(0, 7, (2, 5)),

from functools import partial
ex_25 = partial(excection, exceptions=(2, 5))
assert ( # unittest sequence transformation
    map(ex_25, range(5))
    == [0, 1, 3, 4, 6]
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM