Home > front end >  Python randomly matching two arrays, e.g. Owners and Gifts
Python randomly matching two arrays, e.g. Owners and Gifts

Time:12-21

Suppose I have two arrays

people = ['tom', 'dick', 'harry']
gifts = ['toms', 'dicks', 'harrys']

and I want to randomly assign a person to a gift, however I don't want to assign them to their own.

I've had trouble because solutions like random.choice don't know about the constraint of not picking a person's own gift. My current hack is to just shift the gifts list by random(1, n-1) but obviously thats not that random.

I feel like I'm missing something obvious? Any common way to do this?

CodePudding user response:

This should work for you.

import random

people = ['tom', 'dick', 'harry', 'arne']
gifts = ['toms', 'dicks', 'harrys', 'arne']

# assign each person a gift randomly but not at the
# same index and don't repeat the same gifts twice so remove them

gift_dict = {}
for people_index in range(len(people)):
    gift_choice = people_index
    while gift_choice == people_index:
        gift_choice = gifts.index(random.choice(gifts))
    gift_dict[people[people_index]] = gifts[gift_choice]
    gifts.pop(gift_choice)

print(gift_dict)

output

{'tom': 'harrys', 'dick': 'arne', 'harry': 'dicks', 'arne': 'toms'}

CodePudding user response:

You can use random.shuffle() to shuffle one of your lists, then you can zip() them. This should solve the issue without having to worry about memory.

import random
people = ['tom', 'dick', 'harry']
gifts = ['toms', 'dicks', 'harrys']
random.shuffle(gifts)
results = dict(zip(people, gifts))
print(results)

CodePudding user response:

Assuming that no one gets more than one gift (if they can you might check out itertools.product). The trick is for every person find any "valid receivers" to apply random.choice() to. The main criteria seems to be that you can't give to yourself or to the person who gave to you:

I'm sure there are going to be more efficient solutions, but this will get you started:

import random

givers = ['tom', 'dick', 'harry', "joe"]
receivers  = givers.copy()
receivers_givers = {}
for giver in givers:
    # ---------------------
    # You can't give to yourself or to the person who gave to you.
    # ---------------------
    valid_receivers  = [reciever for reciever in receivers  if reciever not in (giver, receivers_givers.get(giver))]
    # ---------------------

    receiver = random.choice(valid_receivers)
    receivers.remove(receiver)
    receivers_givers[receiver] = giver

for reciever, giver in receivers_givers.items():
    print(f"{giver} gifts to {reciever}")

That should give you something like:

tom gifts to joe
dick gifts to harry
harry gifts to tom
joe gifts to dick
  • Related