Skip to content Skip to sidebar Skip to footer

How To Merge Two Elements Of Two Lists In Python At Random And Ensure Resulting Entries Are All Unique?

I have two lists, A and B, with an equal number of elements, although the elements in each list are not necessarily distinct. I would like to form a new list by coupling the elemen

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?"