3

I'm trying to fill lists with permutations of the same initial list. I don't understand why the following is not working.

parts = [[],[]]
while len(parts[-1]) < 2:
  newval = random.choice([[1,2,3,4],[5,6,7,8]])
  for part in parts:
    random.shuffle(newval)
    part.append(newval)

Expected result would be something like: [[[6,7,8,5],[1,3,4,2]],[[5,8,6,7],[4,2,3,1]]]

2 Answers 2

6

random.shuffle works in-place and consequently modifies newval. You have to make a copy when appending to part otherwise the same list (or list reference) is shuffled and stored in part.

import random

parts = [[],[]]
while len(parts[-1]) < 2:
  newval = random.choice([[1,2,3,4],[5,6,7,8]])
  for part in parts:
    random.shuffle(newval)
    part.append(newval[:])

print(parts)

possible outputs:

[[[3, 1, 2, 4], [5, 7, 6, 8]], [[1, 2, 4, 3], [6, 7, 5, 8]]]
[[[1, 3, 2, 4], [4, 2, 1, 3]], [[2, 4, 3, 1], [4, 3, 2, 1]]]
[[[7, 5, 6, 8], [3, 2, 4, 1]], [[8, 5, 6, 7], [1, 4, 3, 2]]]
Sign up to request clarification or add additional context in comments.

4 Comments

or use slicing for list copy newval[:]
better, you are right. In that case we know that this is a list, but this is more elegant, I admit (possibly slightly faster too)
Merci Jean-François ! It works! I think I got it but I'm not sure: in the for loop, I was appending a reference to newval, not its value, so at the end the last shuffled array was being copied everywhere. Is that it?
Exactly. Shuffle works in place but a lot of people try to get its return value or make the mistake you did.
3

Because in Python everything is reference. When you append the value to the array, in fact you add the reference to the place in memory where the value is stored.

Say, you have assigned the list to the first element. When on the next iteration you re-shuffle this list, you change the value in the memory. Thus, the value you will when accessing the element you appended on previous step is also changed.

To fix this, try appending copy.copy(newval) instead of just newval (do not forget to import copy)

Here is your code changed accordingly:

import copy
parts = [[],[]]
while len(parts[-1]) < 2:
    newval = random.choice([[1,2,3,4],[5,6,7,8]])
    for part in parts:
        random.shuffle(newval)
        part.append(copy.copy(newval))

1 Comment

Your answer is good, but it could be improved by adding a code example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.