Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inverse of random.shuffle()?

I have a function, for simplicity I'll call it shuffler and it takes an list, gives random a seed 17 and then prints that list shuffled.

def shuffler( n ):
   import random
   random.seed( 17 )
   print( random.shuffle( n ) )

How would I create another function called unshuffler that "unshuffles" that list that is returned by shuffler(), bringing it back to the list I inputted into shuffler() assuming that I know the seed?

like image 403
Tethered_ Avatar asked Oct 26 '14 20:10

Tethered_


3 Answers

Just wanted to contribute an answer that's more compatible with functional patterns commonly used with numpy. Ultimately this solution should perform the fastest as it will take advantage of numpy's internal optimizations, which themselves can be further optimized via the use of projects like numba. It ought to be much faster than using conventional loop structures in python.

import numpy as np

original_data = np.array([23, 44, 55, 19, 500, 201]) # Some random numbers to represent the original data to be shuffled
data_length = original_data.shape[0]

# Here we create an array of shuffled indices
shuf_order = np.arange(data_length)
np.random.shuffle(shuf_order)

shuffled_data = original_data[shuf_order] # Shuffle the original data

# Create an inverse of the shuffled index array (to reverse the shuffling operation, or to "unshuffle")
unshuf_order = np.zeros_like(shuf_order)
unshuf_order[shuf_order] = np.arange(data_length)

unshuffled_data = shuffled_data[unshuf_order] # Unshuffle the shuffled data

print(f"original_data: {original_data}")
print(f"shuffled_data: {shuffled_data}")
print(f"unshuffled_data: {unshuffled_data}")

assert np.all(np.equal(unshuffled_data, original_data))
like image 170
Alex Pilafian Avatar answered Oct 07 '22 02:10

Alex Pilafian


Here are two functions that do what you need:

import random
import numpy as np

def shuffle_forward(l):
    order = range(len(l)); random.shuffle(order)
    return list(np.array(l)[order]), order

def shuffle_backward(l, order):
    l_out = [0] * len(l)
    for i, j in enumerate(order):
        l_out[j] = l[i]
    return l_out

Example

l = range(10000); random.shuffle(l)
l_shuf, order = shuffle_forward(l)
l_unshuffled  = shuffle_backward(l_shuf, order)

print l == l_unshuffled
#True
like image 38
Ulf Aslak Avatar answered Oct 07 '22 01:10

Ulf Aslak


Reseed the random generator with the seed in question and then shuffle the list 1, 2, ..., n. This tells you exactly what ended up where in the shuffle.

like image 39
DarthGizka Avatar answered Oct 07 '22 01:10

DarthGizka