所以我在Python中构建一个列表,例如,让我们说前100个整数,但我确实需要所有100个整数,但只有一个样本可以说3个。
import random
def f():
list_ = []
for i in range(100):
list_.append(i)
return list_
def g(list_,k):
return random.sample(list_, k)
print(g(f(),3))
>>>[50, 92, 6]
现在我可以逃避不首先构建整个列表,但直接构建样本,可能是通过添加一个概率,将元素添加到f()
因为如果我构建的是一个庞大的列表,它不是整数而是一些其他对象,那么就内存和计算而言,这种方法可能成本很高。
答案 0 :(得分:3)
def random_no_dups_k_of_n(k, n):
res = list(range(k))
for i in range(k, n):
v = random.randint(0, i) # this is 0-i inclusive
if v == i:
ir = random.randint(0,k-1)
res[ir] = i
return res
这里发生了什么:它是一种伸缩产品。从0
到k-1
的每个元素开始都有k/k
被选中的机会。第一次迭代后k
有1/(k+1)
次被选中的机会,而所有其他人(不仅仅是剩下的,但全部)都有(k-1)/k * k/(k+1) = (k-1)/(k+1)
次被选中的机会。第二次迭代后,k+1
有1/(k+2)
次被选中的机会,而其他所有人都有(k-1)/(k+1) * (k+1)/(k+2) = (k-1)/(k+2)
次被选中的机会。等等。最后,每个号码都有k/n
次被选中的机会。
实际上,我刚看到你可以做random.sample(range(n), k)
。我只是假设它不可用。
编辑 :我得到了上面颠倒的概率。正确的版本应该是:
def random_no_dups_k_of_n(k, n):
res = list(range(k))
for i in range(k, n):
v = random.randint(0, i) # this is 0-i inclusive
if v < k:
ir = random.randint(0,k-1)
res[ir] = i
return res
从0
到k-1
的每个元素开始都有k/k
被选中的机会。第一次迭代后k
有k/(k+1)
次被选中的机会,而所有其他人(不仅仅是剩下的,但全部)都有k/k*((k-1)/k * k/(k+1) + 1(k+1) = k/(k+1)
次被选中的机会。第二次迭代后,k+1
有k/(k+2)
的机会被选中,而其他所有人都有k/(k+1)*((k-1)/k * k/(k+2) + 2/(k+2))= k/(k+2)
次被选中的机会。
这实际上会折叠所有计算,以便在k/(k+m)
步之后为每个元素提供m
个机会。