How To Merge Two Elements Of Two Lists In Python At Random And Ensure Resulting Entries Are All Unique?
Solution 1:
Well, there is no reason for you to shuffle both lists. The pairing will not get "more random".
Update: I've posted a different solution than my original one. It's recursive, and is guaranteed to always return a valid answer, or None if one is not possible.
from random import shuffle
defmerge(events, actors, index=None):
"""Returns list of unique pairs of events and actors, none of which may on index"""iflen(events) == 0:
return []
if index isNone:
index = set()
merged = None
tried_pairs = set()
for event in events:
for i, actor inenumerate(actors):
pair = (event, actor)
if pair notin index and pair notin tried_pairs:
new_index = index.union([pair])
rest = merge(events[1:], actors[:i]+actors[i+1:], new_index)
if rest isnotNone:
# Found! Done.
merged = [pair] + rest
breakelse:
tried_pairs.add(pair)
if merged isnotNone:
breakreturn merged
if __name__ == '__main__':
_events = ['P1','P1','P1','P2','P2','P2','P3','P3','P3','P4','P5','P6','P7','P7']
_actors = ['IE','IE','ID','ID','IA','IA','IA','IC','IB','IF','IG','IH','IH','IA']
shuffle(_events)
edgelist = merge(_events, _actors)
if edgelist isnotNone:
print'Solution obtained: 'for item in edgelist:
print item
else:
print'No possible solution with these events and actors.'
Note: the "index" variable is similar to checking edgelist, on the OP's solution. The "tried_pairs" variable is just an optimisation for each specific recursion step, to avoid retrying the same pair over and over again (if, for instance, there are several consecutive identical items in actors).
Solution 2:
This seems to work OK, however I'm not completely sure how well it will scale...
# Create tuples of lists of actors and events for testing
testcases = [
(['P1','P1','P1','P2','P2','P2','P3','P3','P3','P4','P5','P6','P7','P7'],
['IE','IE','ID','ID','IA','IA','IA','IC','IB','IF','IG','IH','IH','IA']),
(['P1','P1','P1','P1','P1','P1','P1','P2','P2','P2','P2','P2','P2','P2'],
['IE','IE','IE','IE','IE','IE','IE','ID','ID','ID','ID','ID','ID','ID']),
(['P1','P2','P3','P4','P5','P6','P7','P8','P9','PA','PB','PC','PD','PE'],
['IE','IE','IE','IE','IE','IE','IE','ID','ID','ID','ID','ID','ID','ID']),
]
events, actors = testcases[0]
import random
defrandom_choice(items):
""" yield list items in random order """
items = items[:] # preserve input argument
random.shuffle(items)
while items:
yield items.pop()
pairs = set()
for event in random_choice(events):
for index in random_choice(range(len(actors))):
pair = (event, actors[index])
if pair notin pairs: # unique?
pairs.add(pair)
actors.pop(index)
break# Display the solution (in sorted order)print'Solution obtained has %d unique pairs: ' % len(pairs)
for item insorted(list(pairs)):
print item
I used ideas from both the answers to the question How can you select a random element from a list, and have it be removed?.
Solution 3:
# Create a list of actors and events for testing
events = ['P1','P1','P1','P2','P2','P2','P3','P3','P3','P4','P5','P6','P7','P7']
actors = ['IE','IE','ID','ID','IA','IA','IA','IC','IB','IF','IG','IH','IH','IA']
# Randomize the elements
shuffle(events)
# Merge the two lists into a new list of pairs
edgelist = zip(events,actors)
# remove duplicates
x = set(edgelist)
# If there were not enough unique elements : add new ones as needed.whilelen(x)<len(edgelist):
x.add((choice(events), choice(actor)))
# Display the solutionprint'Solution obtained: 'for item in x:
print item
Post a Comment for "How To Merge Two Elements Of Two Lists In Python At Random And Ensure Resulting Entries Are All Unique?"