Python:创建随机整数列表,其中状态 space 是有限的
Python: create list of random integers where state space is limted
我想创建一个从区间 [0,n[(n 通常比 x 大得多)中选择的 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]
或...
这是期望的结果,但是,是否有任何faster/more紧凑的方法来做到这一点?
编辑:
所有这些解决方案都可以正常工作,因此我必须进行一些速度比较才能决定接受哪一个。事实证明——这并不奇怪——预先生成所有允许的值然后从中选择,对于大的 n 值来说效率非常低,而 while 循环很容易获胜。因此,我接受了 hgwells 的回答,因为他的版本不仅比我的 while-loop 更快,而且应该消耗更少的内存。
非常感谢您的所有回答;我可以从他们身上学到很多东西!
根据 n
、x
和 ignore
的值,构建所有允许值的列表并重复调用 [=15] 可能更有效=] 创建您的列表。
例如,一个(尽管很慢)实现是:
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
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 个号码。
这是一个基于生成器的解决方案。但我真的不知道它能在多大程度上改善你的解决方案
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)
基于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))
我想创建一个从区间 [0,n[(n 通常比 x 大得多)中选择的 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]
或...
这是期望的结果,但是,是否有任何faster/more紧凑的方法来做到这一点?
编辑: 所有这些解决方案都可以正常工作,因此我必须进行一些速度比较才能决定接受哪一个。事实证明——这并不奇怪——预先生成所有允许的值然后从中选择,对于大的 n 值来说效率非常低,而 while 循环很容易获胜。因此,我接受了 hgwells 的回答,因为他的版本不仅比我的 while-loop 更快,而且应该消耗更少的内存。
非常感谢您的所有回答;我可以从他们身上学到很多东西!
根据 n
、x
和 ignore
的值,构建所有允许值的列表并重复调用 [=15] 可能更有效=] 创建您的列表。
例如,一个(尽管很慢)实现是:
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
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 个号码。
这是一个基于生成器的解决方案。但我真的不知道它能在多大程度上改善你的解决方案
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)
基于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))