我想创建一个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循环更快,而且还应该消耗更少的内存。
非常感谢所有答案;我可以从他们所有人那里学到很多东西!
答案 0 :(得分:1)
根据n
,x
和ignore
的值,构建所有允许值的列表并使用重复调用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))