-1

Lets say L=[1,2,3,4,5]

How can I create 4 (or maximum of len(L)!) unique random orders of L?

Expected result should look like this:

[[2,1,3,4,5],[5,3,2,1,4],[4,3,2,1,5],[5,1,3,2,4]
Gerges
  • 6,269
  • 2
  • 22
  • 44
Mahdi Ghelichi
  • 1,090
  • 14
  • 23
  • Show what you have tried so far. – Michael Butscher Oct 11 '17 at 22:05
  • Look at [`random.choices`](https://docs.python.org/3/library/random.html#random.choices) and [`itertools.permutations`](https://docs.python.org/3/library/itertools.html#itertools.permutations) – Patrick Haugh Oct 11 '17 at 22:08
  • would this `[[1, 2, 3, 4, 5], [1, 2, 3, 5, 4], [1, 2, 4, 3, 5], [1, 2, 4, 5, 3]]` be valid result for you? – RomanPerekhrest Oct 11 '17 at 22:10
  • I did not look at itertools. I tried random.choices but the problem was omitting the repeated random samples. There is no guarantee that two randomly generated samples are not the same. – Mahdi Ghelichi Oct 11 '17 at 22:31

2 Answers2

2

As pointed out in this post, you can use itertools to generate all possible permutations of the list:

all_perms = list(itertools.permutations(L))

then if you only want 4 random choices (without replacement) of all possible permutations, you can do something like:

random.sample(all_perms, k=4)
Gerges
  • 6,269
  • 2
  • 22
  • 44
  • That's going to generate a lot more permutations than necessary, though. That might not be a big deal with a length-4 list, but it's completely infeasible for something like length-20. – user2357112 Oct 11 '17 at 22:28
  • Yes, I was about to comment on your answer... its good to have a more efficient alternative for larger lists. I wonder if this can be solved with numpy. – Gerges Oct 11 '17 at 22:30
2

Fairly standard approach: pick random samples and throw away duplicates for a small sample, or partial shuffle if you're generating a sample that covers most of the sample space.

import itertools
import math
import random

def n_random_permutations(n, l):
    if n * 3 < math.factorial(len(l)):
        # rejection sampling
        # generate samples and throw them away if we already picked them.
        samples = set()

        while len(samples) < n:
            sample = list(l)
            random.shuffle(sample)
            samples.add(tuple(sample))

        samples = list(samples)
        random.shuffle(samples)
        return samples
    else:
        # generate every possible permutation and pick n of them.
        permutations = list(itertools.permutations(l))
        return random.sample(permutations, n)
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Good alternative for larger arrays! One thing to consider though is that `math.factorial(len(l))` might go out of range due to multiplication by `0.3` which casts it to `float`. Doing `if n/0.3 < math.factorial(len(l))` would solve overflow error for larger lists... – Gerges Oct 11 '17 at 22:43