0

I want to create a nested list by a repetition of a simple list, say

x = ['a','b','c']
y = [x] * 3

Which results in

[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]

When I change an element of one of the nested lists, the corresponding elements in all other lists also change:

y[0][0] = 'z'

[['z', 'b', 'c'], ['z', 'b', 'c'], ['z', 'b', 'c']]

What should I do in order to get the following list instead of the above change in all list items?

[['z', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
LSchueler
  • 1,414
  • 12
  • 23
  • 1
    This answer on shallow copy vs deep copy might help you: https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list – Shibani Mar 20 '18 at 04:43

2 Answers2

1

Lists are references in python. Therefore you're making a list of 3 references to the x list with your code the way it is. There are several ways to work around this, and make a real copy of your list, slice is one of them. Slice will return a new list from the primary list based on the slice range.

Below I simply use loop to loop the number of times you wanted (3) and slice the full range of the x list each time so I return a copy of it. I then just append the resulting slice to the y list.

Maybe not the prettiest, but solves this problem.

x = ['a','b','c']
y = []
for n in range(3):
    y.append(x[:])

print(y)

y[0][0] = 'z'

print(y)

Output:

[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
[['z', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
Dave
  • 592
  • 3
  • 15
1

Let's start from the beginning and explore it a little deep:

So Suppose you have two list:

list_1=['01','98']
list_2=[['01','98']]

And we have to copy both list, now starting from the first list:

So first, let's try by general method of copy:

copy=list_1

Now if you are thinking copy copied the list_1 then you can be wrong, let's check it:

The id() function shows us that both variables point to the same list object, i.e. they share this object.
print(id(copy))
print(id(list_1))

output:

4329485320
4329485320

Surprised ? Ok let's explore it:

So as we know python doesn't store anything in a variable, Variables are just referencing to the object and object store the value. Here object is list but we created two references to that same object by two different variable names. So both variables are pointing to the same object:

so when you do copy=list_1 what actually it's doing:

enter image description here

Here in the image list_1 and copy are two variable names but the object is same for both variable which is list

So if you try to modify copied list then it will modify the original list too because the list is only one there, you will modify that list no matter you do from the copied list or from the original list:

copy[0]="modify"

print(copy)
print(list_1)

output:

['modify', '98']
['modify', '98']

So it modified the original list:

What is the solution then?

Solution:

Now let's move to a second pythonic method of copying list:

copy_1=list_1[:]

Now this method fix the thing what we were facing in first issue let's check it:

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

So as we can see our both list having different id and it means both variables are pointing to different objects so what actually going on here is:

enter image description here

Now let's try to modify the list and let's see if we still face the previous problem:

copy_1[0]="modify"

print(list_1)
print(copy_1)

Output:

['01', '98']
['modify', '98']

So as you can see it is not modifying the original list, it only modified the copied list, So we are ok with it.

So now i think we are done? wait we have to copy the second nested list too so let's try pythonic way:

copy_2=list_2[:]

So list_2 should reference to another object which is copy of list_2 let's check:

print(id((list_2)),id(copy_2))

we get the output:

4330403592 4330403528

Now we can assume both lists are pointing different object so now let's try to modify it and let's see it is giving what we want:

So when we try:

copy_2[0][1]="modify"

print(list_2,copy_2)

it gives us output:

[['01', 'modify']] [['01', 'modify']]

Now, this is little confusing we used the pythonic way and still, we are facing the same issue.

let's understand it:

So when we do:

copy_2=list_2[:]

we are actually copying the outer list only, not the nested list, so nested list is same object for both list, let's check:

print(id(copy_2[0]))
print(id(list_2[0]))

output:

4329485832
4329485832

So actually when we do copy_2=list_2[:] this is what happens:

enter image description here

It creates the copy of list but only outer list copy, not the nested list copy, nested list is same for both variable so if you try to modify the nested list then it will modify the original list too because nested list object is same for both nested list.

So what is the solution?

Solution is deep copy

from copy import deepcopy
deep=deepcopy(list_2)

So now let's check it:

print(id((list_2)),id(deep))

output:

4322146056 4322148040

both id are different, now let's check nested list id:

print(id(deep[0]))
print(id(list_2[0]))

output:

4322145992
4322145800

As you can see both id are different so we can assume that both nested list are pointing different object now.

So when you do deep=deepcopy(list_2) what actually happens:

enter image description here

So both nested list are pointing different object and they have seprate copy of nested list now.

Now let's try to modify the nested list and let's see if it solved the previous issue or not:

so if we do:

deep[0][1]="modify"
print(list_2,deep)

output:

[['01', '98']] [['01', 'modify']]

So, as you can see, it didn't modify the original nested list, it only modified the copied list.

Pang
  • 9,564
  • 146
  • 81
  • 122
Aaditya Ura
  • 12,007
  • 7
  • 50
  • 88