0

Let's say I want to create a nested list with number sequence, and I want no repeated list sequence.

i.e. I would like something like this: [[1,2,3,4],[2,1,3,4],[4,2,3,1]] ,where the len of list depend on how many non repeated number sequence I could generate in limited attempt (four attempts in below case)

So here my first attempt:

import random
rng = random.Random()
bd =list(range(4))
i = 0
result =[]

while i <4:
    rng.shuffle(bd)
    if bd not in result:
        result.append(bd)
    i +=1
print(result)

I created the a list bd = [0,1,2,3] first before entering the while loop.

While running the above code, I got surprisingly only one element in my nested list every time.

Result: [[1, 2, 0, 3]]

But if I modify the code a little bit, it works as I expected. Here my modified code:

import random
rng = random.Random()
i = 0
result =[]

while i <4:
    bd =list(range(4))
    rng.shuffle(bd)
    if bd not in result:
        result.append(bd)
    i +=1
print(result)

Result: [[3, 2, 0, 1], [1, 0, 3, 2], [0, 1, 3, 2]]

What I do is just reset the list bd in every loop over again.

As per my understanding the list bd would be shuffled in every loop, so resetting bd to [0,1,2,3] should be meaningless. Could somebody explain to me why the modified code works? Thanks.

Le0
  • 107
  • 1
  • 8
  • Also see http://stackoverflow.com/questions/240178/python-list-of-lists-changes-reflected-across-sublists-unexpectedly – PM 2Ring Feb 01 '16 at 11:31

4 Answers4

3

Lists and similar objects in Python are referred to by reference. Consider the following simple example:

a_list = [1,2,3,4,5]
another_list = []

for i in range(5):
    another_list.append(a_list)
    a_list[0] = i + 10

print(another_list)

You would expect the output to be:

[[10, 2, 3, 4, 5], [11, 2, 3, 4, 5], [12, 2, 3, 4, 5], [13, 2, 3, 4, 5], [14, 2, 3, 4, 5]]

However, the output you see is:

[[14, 2, 3, 4, 5], [14, 2, 3, 4, 5], [14, 2, 3, 4, 5], [14, 2, 3, 4, 5], [14, 2, 3, 4, 5]]

Every time you call another_list.append(a_list), you append a reference to a_list. You then change a_list, and previously appended references point to the changed list.

At the end, a_list is equal to [14, 2, 3, 4, 5], and another_list contains five identical references to this list.


Back to your case. To prevent this from happening to you, you can create a copy of the list every time you append it, as documented here:

import random
rng = random.Random()
i = 0
result =[]

while i <4:
    bd =list(range(4))
    rng.shuffle(bd)
    if bd not in result:
        # Use [:] to create a slice of bd which actually contains the whole list
        result.append(bd[:])
    i +=1
print(result)
Community
  • 1
  • 1
Archimaredes
  • 1,397
  • 12
  • 26
1

In your first attempt, you're shuffling and appending the same list to result every time. Try using a copy by taking a slice of the whole list: bd[:] is an entirely independent object that won't get changed when you shuffle the original bd next time round the loop.

import random
rng = random.Random()
bd =list(range(4))
i = 0
result =[]

while i <4:
    rng.shuffle(bd)
    if bd not in result:
        result.append(bd[:])
    i +=1
print(result)

Output:

[[2, 1, 3, 0], [1, 2, 3, 0], [0, 3, 2, 1]]
xnx
  • 24,509
  • 11
  • 70
  • 109
1

This happend because you append bd to result and in the next iteration you use bd, they have the same reference.
In the second one you generate a new list(different reference)in each iteration.

Kenly
  • 24,317
  • 7
  • 44
  • 60
1

There's one little trouble with your code: shuffle performs an in-place change, so it changes the object your variable references. By running first code, you'll always get one result -- the last shuffling operation. To avoid this you should append a copy of list:

import random
rng = random.Random()
bd =list(range(4))
i = 0
result =[]

while i <4:
    rng.shuffle(bd)
    if bd not in result:
        result.append(bd[:])
    i +=1
print(result)
thodnev
  • 1,564
  • 16
  • 20