david.keck
david.keck

Reputation: 23

Randomizing two lists and maintaining order in Python 3.4

I'm basically asking the exact same question as was asked here, but for Python 3.4.0.

In 3.4.0, this code:

a = ["Spears", "Adele", "NDubz", "Nicole", "Cristina"]
b = [1, 2, 3, 4, 5]

combined = zip(a, b)
random.shuffle(combined)

a[:], b[:] = zip(*combined)

does not work. What is the correct way to do this in 3.4.0?

Upvotes: 2

Views: 1623

Answers (4)

John La Rooy
John La Rooy

Reputation: 304147

If memory was tight, you can write your own shuffle function to avoid the need to create the zipped list. The one from Python is not very complicated

def shuffle(self, x, random=None, int=int):
    """x, random=random.random -> shuffle list x in place; return None.

    Optional arg random is a 0-argument function returning a random
    float in [0.0, 1.0); by default, the standard random.random.

    Do not supply the 'int' argument.
    """

    randbelow = self._randbelow
    for i in reversed(range(1, len(args[0]))):
        # pick an element in x[:i+1] with which to exchange x[i]
        j = randbelow(i+1) if random is None else int(random() * (i+1))
        x[i], x[j] = x[j], x[i]

Your function could be this:

def shuffle2(a, b):
    for i in reversed(range(1, len(a))):
        j = int(random.random() * (i+1))
        a[i], a[j] = a[j], a[i]
        b[i], b[j] = b[j], b[i]

To shuffle an arbitrary number of lists in unison

def shuffle_many(*args):
    for i in reversed(range(1, len(args[0]))):
        j = int(random.random() * (i+1))
        for x in args: 
            x[i], x[j] = x[j], x[i]

eg

>>> import random
>>> def shuffle_many(*args):
...     for i in reversed(range(1, len(args[0]))):
...         j = int(random.random() * (i+1))
...         for x in args: 
...             x[i], x[j] = x[j], x[i]
... 
>>> a = ["Spears", "Adele", "NDubz", "Nicole", "Cristina"]
>>> b = [1, 2, 3, 4, 5]
>>> shuffle_many(a, b)
>>> a
['Adele', 'Spears', 'Nicole', 'NDubz', 'Cristina']
>>> b
[2, 1, 4, 3, 5]

Upvotes: 2

roippi
roippi

Reputation: 25954

In python 3, zip returns a zip object (i.e. it's itertools.izip from python 2).

You need to force it to materialize the list:

combined = list(zip(a, b))

Upvotes: 5

Peter DeGlopper
Peter DeGlopper

Reputation: 37319

In Python 3, zip returns an iterator rather than a list, so cast it to a list before shuffling it:

combined = list(zip(a, b))

Upvotes: 0

happydave
happydave

Reputation: 7187

Change combined = zip(a,b) to combined = list(zip(a,b)). You need a list, not an iterator, in order to shuffle in place.

Upvotes: 0

Related Questions