以下代码可能会有所帮助。它会弹出一个随机元素,直到iterable 的(副本)为空,然后从整个列表重新开始。缺点是每个项目都被挑选一次,然后才能第二次挑选一个项目。但是,从输出中可以看出,项目的分布最终大致相等。
import random
def equal_distribution_combinations(iterable, n, csize):
"""
Yield 'n' lists of size 'csize' containing distinct random elements
from 'iterable.' Elements of 'iterable' are approximately evenly
distributed across all yielded combinations.
"""
i_copy = list(iterable)
if csize > len(i_copy):
raise ValueError(
"csize cannot exceed len(iterable), as elements could not distinct."
)
for i in range(n):
comb = []
for j in range(csize):
if not i_copy:
i_copy = list(iterable)
randi = random.randint(0, len(i_copy) - 1)
# If i_coppy was reinstantiated it would be possible to have
# duplicate elements in comb without this check.
while i_copy[randi] in comb:
randi = random.randint(0, len(i_copy) - 1)
comb.append(i_copy.pop(randi))
yield comb
编辑
对 Python 3 致歉。对 Python 2 函数的唯一更改应该是 range -> xrange。
编辑 2(回答评论问题)
equal_distribution_combinations 应该导致任何n、csize 和iterable 的长度均匀分布,只要csize 不超过len(iterable)(因为组合元素不能不同)。
这是使用您评论中的特定数字进行的测试:
items = range(30)
item_counts = {k: 0 for k in items}
for comb in equal_distribution_combinations(items, 10, 10):
print(comb)
for e in comb:
item_counts[e] += 1
print('')
for k, v in item_counts.items():
print('Item: {0} Count: {1}'.format(k, v))
输出:
[19, 28, 3, 20, 2, 9, 0, 25, 27, 12]
[29, 5, 22, 10, 1, 8, 17, 21, 14, 4]
[16, 13, 26, 6, 23, 11, 15, 18, 7, 24]
[26, 14, 18, 20, 16, 0, 1, 11, 10, 2]
[27, 21, 28, 24, 25, 12, 13, 19, 22, 6]
[23, 3, 8, 4, 15, 5, 29, 9, 7, 17]
[11, 1, 8, 28, 3, 13, 7, 26, 16, 23]
[9, 29, 14, 15, 17, 21, 18, 24, 12, 10]
[19, 20, 0, 2, 25, 5, 22, 4, 27, 6]
[12, 13, 24, 28, 6, 7, 26, 17, 25, 23]
Item: 0 Count: 3
Item: 1 Count: 3
Item: 2 Count: 3
Item: 3 Count: 3
Item: 4 Count: 3
Item: 5 Count: 3
Item: 6 Count: 4
Item: 7 Count: 4
Item: 8 Count: 3
Item: 9 Count: 3
Item: 10 Count: 3
Item: 11 Count: 3
Item: 12 Count: 4
Item: 13 Count: 4
Item: 14 Count: 3
Item: 15 Count: 3
Item: 16 Count: 3
Item: 17 Count: 4
Item: 18 Count: 3
Item: 19 Count: 3
Item: 20 Count: 3
Item: 21 Count: 3
Item: 22 Count: 3
Item: 23 Count: 4
Item: 24 Count: 4
Item: 25 Count: 4
Item: 26 Count: 4
Item: 27 Count: 3
Item: 28 Count: 4
Item: 29 Count: 3
可以看出,项目是均匀分布的。