pacdev
pacdev

Reputation: 581

How to build unique random couple from a single list

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

Answers (2)

wjandrea
wjandrea

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 of x 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

not_speshal
not_speshal

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

Related Questions