It's that time of year again that programmers want to shuffle a list such that no element resides on its original position (at least in the Netherlands, we celebrate Sinterklaas and pick straws for deciding who writes who a poem). Does anyone have a nice Python single statement for that?
So, input example: range(10)
Output example: [2,8,4,1,3,7,5,9,6,0]
Wrong output would be [2,8,4,1,3,5,7,9,6,0]
because the 5
is at its original position. This would mean that person 5 must write a poem to himself and that is less fun.
edit Many people repeat the assignment just as long as needed to get lucky and find that in fact the solution is satisfactory. This is a bad approach as in theory this can take infinitely long. The better approach is indeed suggested by Bart, but I can't get that into a oneliner for one reason or another...
edit By oneliner, I mean single statement. As it appears, Python is also able to compress multiple statements on a single line. I didn't know that. There are currently very nice solutions only using the semicolon to mimic multiline behaviour on a single line. Hence: "can you do it in a single statement?"
I found shuffle can be abused into solving this
The distribution is not uniform however this was not a requirement.
For a uniform distribution, this (longer) version can be used
How it works
Here is the code for
random.shuffle()
Both solutions work by targeting the line
j = int(random() * (i+1))
The first(non uniform) effectively makes the line work like this
So instead of a range of (1..i) we obtain (0..i-1)
The second solution replaces
random()
with a function that always returns 1, and usesrandint
instead ofint
. So the line now works like this