0

I have a piece of code that should be updating a single item in a list but instead updates the entire list.

Here is the code

a = [
  [(0, 0), (3, 4)]
]
board = [[0] * 5] * 5

for solution in a:
    for _x, _y in solution:
        board[_x][_y] = 1

print(board)

Expected output:

1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 1
0 0 0 0 0

Actual output:

1 0 0 0 1

1 0 0 0 1

1 0 0 0 1

1 0 0 0 1

1 0 0 0 1
Caleb Njiiri
  • 1,563
  • 1
  • 11
  • 20
  • 1
    your board is made up of the same reference to the same object, `[0]`, when you update the actual object yourself you update every reference to it as well, you can verify by doing `id(board[0]) == id(board[n])` where `n <= len(board)` – gold_cy Nov 28 '19 at 13:53
  • `board[0] is board[1] -> True` – Booboo Nov 28 '19 at 14:06

2 Answers2

0

Your problem resides in this line:

board = [[0] * 5] * 5

[[0] * 5] * 5 replicates the resulting list of [0, 0, 0, 0, 0] five times so that the reference remains the same across the board:

print([id(i) for i in board])
[59200896, 59200896, 59200896, 59200896, 59200896]

This makes it impossible to make the change individually.

Instead, do this:

board = [[0] * 5 for _ in range(5)]

print([id(i) for i in board])
[45118008, 45045120, 43900680, 43899760, 45119088]

The list comprehension will create a distinct object reference for each inner list, and the objects can now be updated individually:

[
  [1, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 1],
  [0, 0, 0, 0, 0]
]
r.ook
  • 13,466
  • 2
  • 22
  • 39
  • 1
    Cool. I never knew that `*` operator works this way on the mutable objects. Thanks for this. I thought it was a bug or something. –  Nov 28 '19 at 14:01
  • 1
    That's right. If your starting object wasn't an immutable `int`, you'll also need to change the `[0] * 5` part accordingly to avoid replicating the references. It's important to keep object references in mind, you'll come across this issue periodically. – r.ook Nov 28 '19 at 14:03
0

try the below code

a = [
  [(0, 0), (3, 4)]
]
board = [x[:] for x in [[0] * 5] * 5]

for solution in a:
    for _x, _y in solution:
        board[_x][_y] = 1

print(board)
dassum
  • 4,727
  • 2
  • 25
  • 38
  • Thanks for the solution. Although, I was more interested in knowing the reason behind this behaviour. –  Nov 28 '19 at 14:05