1

I would like to shuffle a 1-d numpy array, with the constraint that no elements match the corresponding elements (ie., same index) from another array of the same shape. It can be assumed that all elements of each array are unique.

For example,

a = np.arange(10)
b = a.copy()
np.random.shuffle(b)
np.where(a==b) # This should be empty

What's the best way? Any ideas?

Christopher Brown
  • 537
  • 1
  • 5
  • 14
  • You could try just reshuffling over and over until your condition is met. – BrenBarn Oct 24 '14 at 18:41
  • 3
    This is called a [derangement](http://en.wikipedia.org/wiki/Derangement). For large `n`, the probability that a random permutation of a list has no fixed points is roughly 1/e, so it's safe to keep reshuffling until you get lucky. On the other hand, an algorithm to generate a derangement is given [here](http://www.lsi.upc.edu/~conrado/research/talks/analco08.pdf). – jme Oct 24 '14 at 18:51
  • Does this answer your question? [Generate a random derangement of a list](https://stackoverflow.com/questions/25200220/generate-a-random-derangement-of-a-list) – Gal Avineri Sep 19 '22 at 13:22

2 Answers2

1

Adapted from georg's answer here

def random_derangement(n):
    while True:
        v = np.arange(n)
        for j in np.arange(n - 1, -1, -1):
            p = np.random.randint(0, j+1)
            if v[p] == j:
                break
            else:
                v[j], v[p] = v[p], v[j]
        else:
            if v[0] != 0:
                return v
Community
  • 1
  • 1
Christopher Brown
  • 537
  • 1
  • 5
  • 14
1
def random_derangement(N):
    original = np.arange(N)
    new = np.random.permutation(N)
    same = np.where(original == new)[0]
    while len(same) != 0:
        swap = same[np.random.permutation(len(same))]
        new[same] = new[swap]
        same = np.where(original == new)[0]
        if len(same) == 1:
            swap = np.random.randint(0, N)
            new[[same[0], swap]] = new[[swap, same[0]]]
    return new
柴俊瑜
  • 11
  • 1
  • Benchmark-wise this one is clearly the fastest ! @Christopher's runs at : `5.85 ms ± 455 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)` whilst this one is `72.2 µs ± 12.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)` therefore 98% faster on average when testing for 2000 permutations. – Samuel Prevost Nov 04 '18 at 10:55