0

I currently have a 2d matrix

matrix =    [['.', '.', '.', '.', '.', '.'], 
             ['.', '.', '.', '.', '.', '.'], 
             ['.', '.', '.', '.', '.', '.'], 
             ['.', '.', '.', 'O', 'O', 'O'], 
             ['.', '.', '.', 'O', '.', '.'],
             ['.', '.', '.', 'O', 'O', '.']]

And I've assigned copy = matrix to make a copy of the matrix. However, I ran into a bug where when I modify copy[], it also modifies matrix[]. I found out that this is a side effect with aliasing and I need to create a deep copy of matrix[].

How do I create a deep copy of a 2d matrix without using imports?

Rae Leng
  • 75
  • 8
  • https://stackoverflow.com/q/2612802/3001761 shows various options, assignment is **not** copying. – jonrsharpe Nov 22 '20 at 22:18
  • 3
    Why would you not want to import [`copy`](https://docs.python.org/3/library/copy.html)? It's part of the Python standard library so you won't need to install anything. – D Malan Nov 22 '20 at 22:19
  • 1
    @DMalan From a learning standpoint, accomplishing tasks without importing any modules seems reasonable. – Red Nov 22 '20 at 22:21
  • `[sub.copy() for sub in matrix]` or any equivalent. This actually isn't a bad thing to do, `copy.deepcopy` is resource intensive because it takes some care to do this correctly for arbitrary inputs (even just avoiding infinite loops). If you have a known structure, it isn't unreasonable to write some deep copy function/ method for it. – juanpa.arrivillaga Nov 22 '20 at 22:39

3 Answers3

4

For a 2D array like your matrix, this should work:

def deep_copy(A):
    return [r[:] for r in A]

It's equivalent to looping over each inner list and copying each of the inner lists. If the values in the inner lists are mutable, this doesn't sufficiently deep-copy but for your use case it should be fine. There's also [[v for v in r] for r in A], which manually copies instead of using a slice to do so.

EDIT: there's also a more general recursive approach that works for your case of using lists of immutable values:

def deep_copy_r(v):
    if isinstance(v, list):
        return [deep_copy_r(e) for e in v]
    return v

Said recursive approach will work up to arbitrary array dimensionality (works for a 3D array, 4D array, up to an N-D array), but only works if lists are the only containing type used.

aleph-null
  • 443
  • 4
  • 11
2

Use a list comprehension to assign a copy of each list in matrix into the other list:

matrix = [['.', '.', '.', '.', '.', '.'], 
          ['.', '.', '.', '.', '.', '.'], 
          ['.', '.', '.', '.', '.', '.'], 
          ['.', '.', '.', 'O', 'O', 'O'], 
          ['.', '.', '.', 'O', '.', '.'],
          ['.', '.', '.', 'O', 'O', '.']]

matrix2 = [l.copy() for l in matrix]

matrix[0][0] = 'O'

print(matrix)
print(matrix2)

Output:

[['O', '.', '.', '.', '.', '.'],
 ['.', '.', '.', '.', '.', '.'],
 ['.', '.', '.', '.', '.', '.'],
 ['.', '.', '.', 'O', 'O', 'O'],
 ['.', '.', '.', 'O', '.', '.'],
 ['.', '.', '.', 'O', 'O', '.']]
[['.', '.', '.', '.', '.', '.'],
 ['.', '.', '.', '.', '.', '.'],
 ['.', '.', '.', '.', '.', '.'],
 ['.', '.', '.', 'O', 'O', 'O'],
 ['.', '.', '.', 'O', '.', '.'],
 ['.', '.', '.', 'O', 'O', '.']]
Red
  • 26,798
  • 7
  • 36
  • 58
0

You can use a simple loop.

m1 = []
for inner in matrix:
    m1.append([])
    for elem in inner:
        m1[-1].append(elem)

print(m1)

This should do the trick. Using list comprehension is a step up to do this, but you should simply use deepcopy() to begin with.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69