We can generate the random combinations using random.sample
, and use a set to ensure we don't generate any combination more than once. Here's a simple demo.
from random import seed, sample
seed(42)
def random_combinations(seq, size, num):
combos = set()
while len(combos) < num:
item = sample(seq, size)
combos.add(tuple(item))
return list(combos)
# test
data = [
(0, 1), (2, 3), (4, 5), (6, 7), (8, 9),
(10, 11), (12, 13), (14, 15), (16, 17), (18, 19),
]
# Make 20 random 3-element combinations
combos = random_combinations(data, 3, 20)
for i, item in enumerate(combos, 1):
print('{:>2}: {}'.format(i, item))
output
1: ((2, 3), (12, 13), (8, 9))
2: ((6, 7), (18, 19), (4, 5))
3: ((2, 3), (16, 17), (18, 19))
4: ((0, 1), (4, 5), (12, 13))
5: ((14, 15), (10, 11), (4, 5))
6: ((2, 3), (0, 1), (8, 9))
7: ((6, 7), (16, 17), (0, 1))
8: ((12, 13), (2, 3), (8, 9))
9: ((6, 7), (14, 15), (8, 9))
10: ((10, 11), (18, 19), (8, 9))
11: ((0, 1), (14, 15), (2, 3))
12: ((18, 19), (10, 11), (6, 7))
13: ((18, 19), (12, 13), (0, 1))
14: ((10, 11), (8, 9), (4, 5))
15: ((8, 9), (2, 3), (6, 7))
16: ((2, 3), (0, 1), (6, 7))
17: ((16, 17), (6, 7), (12, 13))
18: ((2, 3), (12, 13), (18, 19))
19: ((0, 1), (2, 3), (6, 7))
20: ((6, 7), (10, 11), (2, 3))
As tobias_k mentions in the comments, this code is only suitable when num
is not too close to the total number of combinations. If you want < 50% of the total number of combinations it should be fine, but beyond that it will have a high chance of re-generating combinations that it's already generated, which will cause it to loop for a long time.
Note that this code considers ((2, 3), (12, 13), (8, 9))
to be distinct from a tuple containing those 3 pairs in a different order, eg ((2, 3), (8, 9), (12, 13))
.
If you don't want that we can make our items into sets. We need to use frozenset
for this, since normal sets are mutable and therefore unhashable and hence cannot be set items.
from random import seed, sample
seed(42)
def random_combinations(seq, size, num):
combos = set()
while len(combos) < num:
item = sample(seq, size)
combos.add(frozenset(item))
return [tuple(u) for u in combos]
# test
data = [
(0, 1), (2, 3), (4, 5), (6, 7), (8, 9),
(10, 11), (12, 13), (14, 15), (16, 17), (18, 19),
]
# Make 20 random 3-element combinations
combos = random_combinations(data, 3, 20)
for i, item in enumerate(combos, 1):
print('{:>2}: {}'.format(i, item))
output
1: ((0, 1), (2, 3), (6, 7))
2: ((0, 1), (2, 3), (8, 9))
3: ((16, 17), (6, 7), (0, 1))
4: ((12, 13), (2, 3), (18, 19))
5: ((12, 13), (2, 3), (8, 9))
6: ((12, 13), (18, 19), (0, 1))
7: ((8, 9), (4, 5), (10, 11))
8: ((16, 17), (2, 3), (18, 19))
9: ((8, 9), (6, 7), (14, 15))
10: ((0, 1), (4, 5), (12, 13))
11: ((8, 9), (10, 11), (18, 19))
12: ((10, 11), (6, 7), (2, 3))
13: ((0, 1), (14, 15), (2, 3))
14: ((10, 11), (18, 19), (6, 7))
15: ((8, 9), (2, 3), (6, 7))
16: ((4, 5), (6, 7), (18, 19))
17: ((8, 9), (4, 5), (2, 3))
18: ((16, 17), (4, 5), (6, 7))
19: ((16, 17), (6, 7), (12, 13))
20: ((4, 5), (10, 11), (14, 15))