Python:创建状态空间有限的随机整数列表

时间:2015-05-27 16:28:33

标签: python list random

我想创建一个x随机整数列表,它从区间[0,n [(n通常远大于x)中选择,因此应该忽略该区间的某些数量。我实现了如下:

from random import randint

def createRandomList(n, x, ignore=[]):
    myList = []
    while len(myList) < x:
        tempr = randint(0,n-1)
        if tempr not in ignore:
            myList.append(tempr)
    return myList

当我打电话

l = createRandomList(5,2,ignore=[2,3])

我获得了

l = [1,4] #2 and 3 should not appear

l = [0,1]

l = [4,4]

或......

这是理想的结果,但有没有更快/更紧凑的方法呢?

编辑: 所有这些解决方案都运行良好,所以我不得不做一些速度比较来决定接受哪一个。事实证明 - 并非非常令人惊讶地 - 预先生成所有允许的值然后从中进行选择对于大的n值非常低效,并且while循环很容易获胜。因此,我接受了hgwells的回答,因为他的版本不仅比我的while循环更快,而且还应该消耗更少的内存。

非常感谢所有答案;我可以从他们所有人那里学到很多东西!

4 个答案:

答案 0 :(得分:1)

根据nxignore的值,构建所有允许值的列表并使用重复调用random.choice()可能更有效创建你的清单。

例如,一个(尽管很慢)实现将是:

def createRandomList(n, x, ignore=[]):
    srcList = [i for i in range(n) if i not in ignore]
    destList = [random.choice(srcList) for i in range(x)]
    return destList

答案 1 :(得分:1)

from random import randint

def createRandomList(n, x, ignore=[]):
    available_numbers = [elem for elem in range(n) if elem not in ignore]
    myList = [available_numbers[randint(0, len(available_numbers) - 1)] for _ in range(x)]
    return myList

在此方法中,首先创建从0到n-1的数字列表,而忽略数字。之后,您从此列表中选择了x个数字。

答案 2 :(得分:1)

这是一个基于生成器的解决方案。但我真的不知道它会改善你的解决方案

from random import randint

def randGen(n, x, ignore=[]):
    index = 0
    while index < x:
        temp = randint(0, n-1)
        if temp not in ignore:
            index += 1
            # yield the temp value and wait for
            # the next call
            yield temp

# you could now create your list 
# myList = [i  for i in randGen(5, 2, [2,3])]
# or as Mark pointed out
myList = list(randGen(5,2,[2,3]))
print(myList)

# or use the generator items when you need them
for i in randGen(5, 2, [2,3]):
    # do something with i
    print(i)

答案 3 :(得分:1)

基于itertools的生成器方法:

from itertools import count, islice, ifilterfalse  # just 'filterfalse' in Py3
from random import randint
def random_list(limit, size, ignore={}):  # ignore should be a set for O(1) lookups
    ints = (randint(0, limit-1) for _ in count())  # generate randints in range
    filtered = ifilterfalse(ignore.__contains__, ints)  # filter out the rejects
    for i in islice(filtered, size):  # limit the size to what we want and yield
        yield i
    # in Python 3 you don't need the for-loop, simply:
    # yield from islice(filtered, size) 

print list(random_list(5, 2, {2, 3})
# [1, 4]

这可以叠加成一个单行,但打破它可以提高可读性:

l = list(islice(ifilterfalse({2, 3}.__contains__, (randint(0, 4) for _ in count())), 2))