Reputation: 581
I want to find random couples on a single list with different members.
Here is my code:
import random
def alea_couple(members):
couples = []
for p in members:
possibles = [r for r in members if r!=p and r not in [elem[1] for elem in couples]]
couples.append((p, random.choice(possibles)))
return couples
my_members = ["member1", "member2", "member3", "member4"]
random.shuffle(my_members)
alea_couple(my_members)
[('member2', 'member1'),
('member3', 'member4'),
('member1', 'member3'),
('member4', 'member2')]
I am sure there is a better way and more elegant way to do this with itertools.combinations
do you have a piece of advice ?
Upvotes: 0
Views: 184
Reputation: 32928
Here's an implementation I believe is O(n), though performance might not matter (see note below). First shuffle, then rotate by a random amount. I already implemented a random rotater for another question, so here's something similar:
import random
import collections
def random_rotation(lst):
"""
Rotate a list by a random amount and return a deque.
Similar to "random.shuffle()", but ensures that all elements will move.
"""
n = random.randrange(1, len(lst))
d = collections.deque(lst)
d.rotate(n)
return d
def alea_couple(members):
members = random.sample(members, k=len(members)) # Copy and shuffle in one
pairs = random_rotation(members)
return list(zip(members, pairs))
Example outputs:
>>> my_members = ["member1", "member2", "member3", "member4"]
>>> alea_couple(my_members)
[('member4', 'member3'),
('member1', 'member4'),
('member2', 'member1'),
('member3', 'member2')]
>>> alea_couple(my_members)
[('member3', 'member4'),
('member2', 'member1'),
('member4', 'member3'),
('member1', 'member2')]
Note from the docs:
even for small
len(x)
, the total number of permutations ofx
can quickly grow larger than the period of most random number generators. This implies that most permutations of a long sequence can never be generated. For example, a sequence of length 2080 is the largest that can fit within the period of the Mersenne Twister random number generator.
Upvotes: 1
Reputation: 23146
Try with itertools.permutations
:
import itertools
import random
def alea_couple(members):
perms = [p for p in itertools.permutations(members) if not any(x==y for x, y in zip(members, p))]
return list(zip(members, random.choice(perms)))
>>> alea_couple(["member1", "member2", "member3", "member4"])
[('member1', 'member4'),
('member2', 'member3'),
('member3', 'member1'),
('member4', 'member2')]
>>> alea_couple(["member1", "member2", "member3", "member4"])
[('member1', 'member4'),
('member2', 'member3'),
('member3', 'member2'),
('member4', 'member1')]
Upvotes: 2