在看到每个数字之前需要掷出合理的骰子的次数是多少?
已要求我定义一个运行蒙特卡洛模拟的函数,该函数返回上述问题的估计值。我对解决方案的了解是,我需要:
我对编程特别是Python还是一个新手,所以我很难确定为什么在调用函数时我的语法不产生输出,并希望有人可以帮助我朝正确的方向
这是我的代码:
def roll(n=1000):
trials = []
sides = 6
start = 1
for i in range (n):
for x in range (sides):
collection = [random.randint(1,sides)]
while any([x not in collection]):
collection.append(random.randint(1,6))
trials.append(len(collection))
return sum(trials)/ len(trials)
答案 0 :(得分:2)
无论功能返回什么,您都可能不会打印-这就是为什么它什么也不显示。
使用print(roll())
而不是roll()
打印得到的结果。
您有太多的循环,您的解决方案使用了太多的内存空间。
考虑到不幸,必须掷出1.000.000.000.000次才能获得前6个-您将在列表中保存1.000.000.000.000个其他数字..那就是很多内存。
您可以使用set
来记住看到的数字,并使用计数器来计算找到所有数字所花费的时间:
def roll(sides=6, n=1000):
"""Tests 'n' times to roll all numbers from 1 to 'sides' randomly.
Returns average tries needed to see all numbers over 'n' tries."""
trials = [] # collects all sinly tried counters
for _ in range(n):
seen = set() # empty, will only ever store 6 elements at most
tried = 0 # how long did it take to find all 6?
while len(seen) < sides: # use sides here as well
seen.add(random.randint(1,sides))
tried += 1
trials.append(tried)
return sum(trials)/n
print(roll())
输出(4个开始):
14.878
14.694
14.732
14.516
答案 1 :(得分:0)
您的while
条件并未表达您的期望。您可能想使用列表理解
while any([x not in collection for x in [1, 2, 3, 4, 5, 6])
另外,您不希望3层循环,而只希望两层:一个试验for
,另一个while
试验不完整。一个接近您原始帖子的可行示例是
import random
def roll(n=1000):
trials = []
sides = 6
start = 1
possible_sides = [1, 2, 3, 4, 5, 6]
for i in range (n):
collection = [random.randint(1,sides)]
while any([side not in collection for side in possible_sides]):
collection.append(random.randint(1,6))
trials.append(len(collection))
return sum(trials)/ len(trials)
更有效的解决方案使用set
来有效地完成与以前的解决方案使用any([side not in collection for side in possible_sides])
实现的功能相同的事情:
import random
def roll(n=1000):
trials = []
sides = 6
start = 1
possible_sides = set([1, 2, 3, 4, 5, 6])
for i in range (n):
n_rolls = 0
sides_rolled = set()
while not sides_rolled == possible_sides:
sides_rolled.add(random.randint(1, sides))
n_rolls += 1
trials.append(n_rolls)
return sum(trials)/ len(trials)
或者,甚至更有效地,只需检查Patrick len(sides_rolled) < 6
,如Patrick Artner在回答中所指出。
答案 2 :(得分:0)
通过使用set
而不是列表并更改迭代逻辑,可以大大简化代码:
import random
def roll_till_all_sides_appeared():
sides_seen = set()
n = 0
while len(sides_seen) < 6:
side = random.randint(1, 6)
sides_seen.add(side) # will only be added if it isn't present
n += 1
return n
def test(repetitions):
max_n = float('-inf')
min_n = float('inf')
sum_n = 0
for _ in range(repetitions):
n = roll_till_all_sides_appeared()
max_n = max(max_n, n)
min_n = min(min_n, n)
sum_n += n
print('max:', max_n)
print('min:', min_n)
print('avg:', sum_n / repetitions)
此代码可以像这样使用:
>>> test(10)
max: 32
min: 8
avg: 14.3
>>> test(100)
max: 45
min: 6
avg: 14.13
>>> test(1000)
max: 56
min: 6
avg: 14.749
>>> test(10000)
max: 62
min: 6
avg: 14.6422