randomizing two lists and maintaining order in python

Python

Python Problem Overview


Say I have two simple lists,

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

What I would like to do is randomize a and b but maintain the order. So, something like:

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

I am aware that I can shuffle one list using:

import random
random.shuffle(a)

But this just randomizes a, whereas, I would like to randomize a, and maintain the "randomized order" in list b.

Would appreciate any guidance on how this can be achieved.

Python Solutions


Solution 1 - Python

I'd combine the two lists together, shuffle that resulting list, then split them. This makes use of zip()

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

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

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

Solution 2 - Python

Use zip which has the nice feature to work in 'both' ways.

import random

a = ['Spears', "Adele", "NDubz", "Nicole", "Cristina"]
b = [1,2,3,4,5]
z = zip(a, b)
# => [('Spears', 1), ('Adele', 2), ('NDubz', 3), ('Nicole', 4), ('Cristina', 5)]
random.shuffle(z)
a, b = zip(*z)

Solution 3 - Python

To avoid Reinventing The Wheel use sklearn

from sklearn.utils import shuffle

a, b = shuffle(a, b)

Solution 4 - Python

Note that Tim's answer only works in Python 2, not Python 3. If using Python 3, you need to do:

combined = list(zip(a, b))
random.shuffle(combined)
a[:], b[:] = zip(*combined)

otherwise you get the error:

TypeError: object of type 'zip' has no len()

Solution 5 - Python

There's a simpler way that avoids zipping, copying and all of that heavy stuff. We can shuffle both of them separately, but using the same seed both times, which guarantees that the order of the shuffles will be the same.

import random as rd

A = list("abcde")
B = list(range(len(A)))
fixed_seed = rd.random()
rd.Random(fixed_seed).shuffle(A)
rd.Random(fixed_seed).shuffle(B)

A and B are then:

['e', 'a', 'c', 'b', 'd']
[ 4,   0,   2,   1,   3]

The more generic version, for an arbitrary number of lists:

def shuffle(*xss):
    seed = rd.random()
    for xs in xss:
        rd.Random(seed).shuffle(xs)

Solution 6 - Python

Another way could be

a = ['Spears', "Adele", "NDubz", "Nicole", "Cristina"]
b = range(len(a)) # -> [0, 1, 2, 3, 4]
b_alternative = range(1, len(a) + 1) # -> [1, 2, 3, 4, 5]
random.shuffle(b)
a_shuffled = [a[i] for i in b] # or:
a_shuffled = [a[i - 1] for i in b_alternative]

It is the reverse approach, but could help you nevertheless.

Solution 7 - Python

That's my way:

import random
def shuffleTogether(A, B):
    if len(A) != len(B):
        raise Exception("Lengths don't match")
    indexes = range(len(A))
    random.shuffle(indexes)
    A_shuffled = [A[i] for i in indexes]    
    B_shuffled = [B[i] for i in indexes]
    return A_shuffled, B_shuffled

A = ['a', 'b', 'c', 'd']
B = ['1', '2', '3', '4']
A_shuffled, B_shuffled = shuffleTogether(A, B)
print A_shuffled
print B_shuffled

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohnJView Question on Stackoverflow
Solution 1 - PythonTimView Answer on Stackoverflow
Solution 2 - Pythonuser647772View Answer on Stackoverflow
Solution 3 - PythonNimrod MoragView Answer on Stackoverflow
Solution 4 - PythonAdam_GView Answer on Stackoverflow
Solution 5 - PythonPigView Answer on Stackoverflow
Solution 6 - PythonglglglView Answer on Stackoverflow
Solution 7 - PythonNathan BView Answer on Stackoverflow