76

I want to copy a 2D list, so that if I modify one list, the other is not modified.

For a one-dimensional list, I just do this:

a = [1, 2]
b = a[:]

And now if I modify b, a is not modified.

But this doesn't work for a two-dimensional list:

a = [[1, 2],[3, 4]]
b = a[:]

If I modify b, a gets modified as well.

How do I fix this?

12
  • 7
    A whole lot of the time when people user nested lists and need to copy them in this way, they really want to be using numpy. Commented Mar 29, 2010 at 23:23
  • 1
    imho, that's just a bug in the language. behavior that's different for two cases where it should be identical - typical for interpreted languages. if you have large code, very difficult to debug Commented Apr 2, 2019 at 19:38
  • 1
    @SerhiiPoklonskyi No, it's not a bug. When you do b = a[:], you create a new list b, so for example a.append([5, 6]) will not modify b, as it just changes a. However, the line a[1][0] = 5 will change b because it changes a list that b refers to. Commented Apr 9, 2019 at 1:27
  • @ArtemisFowl doesn't work for me (a[1][0] does not modify b as well). Even if it would, I don't understand how that is relevant. The problem is: when you do a = b.copy(), a becomes a separate place in memory: neither reference nor pointer to b, i.e. it's an independent variable. However, if you do a = b.copy() and b is an array, that does not work. how may there be any logical explanation for that? if b is an array, a = b.copy() MUST create an independent variable. otherwise it's a bug. p.s. no intention to be rude, pls explain to me if I am wrong Commented Apr 9, 2019 at 5:57
  • 5
    @SerhiiPoklonskyi I think the reason that you find this confusing is that you miss-understand Python. Python does not actually have '2-dimensional arrays' as such, it just has lists, which can contain other lists. I will try to demonstrate by means of an example: you define a with a = [[1, 2], [3, 4]]. Then you create a copy of a: b = a.copy. This is a different list, but it contains the same 'sub-lists' this means that changing b, for example b.append([5, 6]) will not change a, however changing a list in b, for example b[0].append(3) will also change the first list of a. Commented Apr 10, 2019 at 18:34

5 Answers 5

95

For a more general solution that works regardless of the number of dimensions, use copy.deepcopy():

import copy
b = copy.deepcopy(a)
Sign up to request clarification or add additional context in comments.

8 Comments

@Dav, you make a valid point. I prefer to always import modules in order to avoid name conflicts instead of handling functions on a case-by-case basis. :)
Note that this will also deepcopy the actual elements in the lists.
@Dav, I disagree, it's generally better to use the module.function() format.
"Namespaces are one honking great idea -- let's do more of those!"
@FogleBird: However, PEP-8 does actually seem to imply that from ... import ... is the norm unless there are namespace conflicts: python.org/dev/peps/pep-0008 (see "Imports").
|
95
b = [x[:] for x in a]

5 Comments

+1 since appropriate. I personally like avoiding copy / deepcopy (very very rarely had a valid use case for them in real life ; the same can be said for a list with more then 2 dimensions imo)
Can you please provide a use case? I'm trying to copy a 2D list, but I'm not sure what to replace with the variable names you provide.
@JohnLocke b is the new list, a is the old one. x is used internally.
for me, path was a 2D array and I wanted to copy path[i] so I did curr_level = [x[:] for x in path[i]]
This is what I call efficient (and clever) programming! (Importing extra modules for something that can be done simply w/o them is inefficient.)
8

Whis b = a[:] doesn't work for nested list(or say muti-dimension list)?

a = [[1, 2],[3, 4]]
b = a[:]

Answer: Though when we are copying the list a using slicing[:] operation but the inner sub-list still refers to the inner-sub list of list b

Note: We can check the reference using id() in python.
Let's understand using an example.

>>> a = [[1,2],[3,4]]
>>> id(a)
140191407209856    # unique id of a
>>> b=a
>>> id(b)
140191407209856
>>> b=a[:]        # Copying list a to b with slicing
>>> id(b)         
140191407209920   # id of list b changed & is not same as id of list a
>>> id(a[0])      
140191407188544
>>> id(b[0])
140191407188544
>>> id(a[0])==id(b[0])  # id of both a[0] & b[1] is same.
True

So, slicing won't change the reference for objects inside the list. You can notice from above that reference of a[0] is the same as b[0].
When you copy a 2D list to another, it adds a reference to it not the actual list.

Instead you can use:

  • b = copy.deepcopy(a)
  • b = [item[:] for item in a]
  • b = [item.copy() for item in a]
  • b = [list(item) for item in a]
  • b = [copy.copy(item) for item in a]
  • b = []; b.extens[a]

Below is the comparison of the time complexity of all available copy methods (source)

  1. 10.59 sec (105.9us/itn) - copy.deepcopy(old_list)

  2. 10.16 sec (101.6us/itn) - pure python Copy() method copying classes with deepcopy

  3. 1.488 sec (14.88us/itn) - pure python Copy() method not copying classes (only dicts/lists/tuples)

  4. 0.325 sec (3.25us/itn) - for item in old_list: new_list.append(item)

  5. 0.217 sec (2.17us/itn) - [i for i in old_list] (a list comprehension)

  6. 0.186 sec (1.86us/itn) - copy.copy(old_list)

  7. 0.075 sec (0.75us/itn) - list(old_list)

  8. 0.053 sec (0.53us/itn) - new_list = []; new_list.extend(old_list)

  9. 0.039 sec (0.39us/itn) - old_list[:] (list slicing)

1 Comment

b = []; b.extend[a] won't work here - it's a shallow copy, like b = [item for item in a] would be.
0

You can use the following for two-dimensional nested arrays: b = [[y for y in x] for x in a]

Comments

0

It is not working because when you do cloning or copy it will create shallow copy. So what is shallow copy and deep copy?

Consider, a is list , a = [1,2,3] now when you create new name b= a[:] or b = a.copy(). (Both will give same result. ) . You need to understand what happens at memory level. When we create copy, address reference for list a & b will be changed as in python everything is pass by reference. However, address of the items in the list will remain the same. Please see below snippet.

[Creating list and printing id's of element] 1

Now, we will create a copy and print id of elements inside copied object.

You can see after creating copy, id's of objects inside list has not changed.

However, id's of both the lists will be different as below:

[Id's are different] 3

This is called shallow copy , in which address of objects inside mutable data type will not changed. So, if you pass mutable data type inside of another mutable data type(which is nothing but 2D list) then address will be the same of inside mutable data type. Hence, change done by using name a, will also be reflected in b. Please see below code snippet.

[2-D list overview.] 4

If your requirement is there should not be any change then you can use deepcopy as below code snipped.

[Deep Copy] 5

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.