Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two-dimensional list wrongly assigning values in python

class Board:

    def __init__(self):
        self.board = self.createBoard()

    def createBoard(self):
        line = []
        for i in range(7):
            line.append(' ')
        board = []
        for i in range(7):
            board.append(line)
        return board

    def showBoard(self):
        line = "| "
        for x in range(len(self.board)):
            for y in range(len(self.board)):
                line += self.board[x][y] + " | "
            print("-" * 29)
            print(line)
            line = "| "
        print("-" * 29)

if __name__ == '__main__':
    board = Board()
    board.showBoard()
    board.board[1][1] = "O"
    board.showBoard()

I was working on a connect-4 python console demo/game when I got stuck on this really weird issue.

The output of the code above is as follows:

-----------------------------
|   | O |   |   |   |   |   | 
-----------------------------
|   | O |   |   |   |   |   | 
-----------------------------
|   | O |   |   |   |   |   | 
-----------------------------
|   | O |   |   |   |   |   | 
-----------------------------
|   | O |   |   |   |   |   | 
-----------------------------
|   | O |   |   |   |   |   | 
-----------------------------
|   | O |   |   |   |   |   | 
-----------------------------

The weird thing is, I never assigned O to all those positions, I only assigned it to the position [1][1].

I had expected the output to be:

-----------------------------
|   |   |   |   |   |   |   | 
-----------------------------
|   | O |   |   |   |   |   | 
-----------------------------
|   |   |   |   |   |   |   | 
-----------------------------
|   |   |   |   |   |   |   | 
-----------------------------
|   |   |   |   |   |   |   | 
-----------------------------
|   |   |   |   |   |   |   | 
-----------------------------
|   |   |   |   |   |   |   | 
-----------------------------

It is extremely likely that I'm missing something obvious and small but I've been looking and trying for over an hour and I really can't find the problem.

It's not like my board.board list is any more odd than any other two-dimensional list.

[[' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' ']]

(It's what I get when I print(board.board))

Copying and pasting that into IDLE I get the following:

>>> a = [[' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' ']]
>>> a[1][1] = "O"
[[' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', 'O', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' ']]

Which gets me the proper board value.

What is so obviously wrong in my code that I'm missing it? I'm pretty sure that when any of you find an answer that I'll shake my head in shame, it's likely that bad.

Enough self-shaming, so why does my code board.board[1][1] = "O" assign the value "O" to the every single row in board.board?

Changing the first 1 to any other number from 0-6 doesn't change anything either. It's all the same.

like image 228
Azeirah Avatar asked Sep 06 '13 23:09

Azeirah


People also ask

Can a python list be 2 dimensional?

Python provides many ways to create 2-dimensional lists/arrays. However one must know the differences between these ways because they can create complications in code that can be very difficult to trace out.

How do you convert a 2D list in python?

You can transpose a two-dimensional list using the built-in function zip() . zip() is a function that returns an iterator that summarizes the multiple iterables ( list , tuple , etc.).


1 Answers

This is explained in the FAQ, under How do I create a multidimensional list?

The problem is in this part of the code:

board = []
for i in range(7):
    board.append(line)

You're creating a list with 7 references to the same list, line. So, when you modify one, the others all change, because they're the same list.

The solution is to create 7 separate lists, like this:

def createBoard(self):
    board = []
    for i in range(7):
        line = []
        for i in range(7):
            line.append(' ')
        board.append(line)
    return board

Or, more simply, make separate copies of the original list:

def createBoard(self):
    line = []
    for i in range(7):
        line.append(' ')
    board = []
    for i in range(7):
        board.append(line[:])
    return board

While we're at it, you could simplify this tremendously by using list comprehensions:

def createBoard(self):
    return [[' ' for j in range(7)] for i in range(7)]

Or, as the FAQ suggests, you might do better to use a smarter multidimensional array object, like the ones numpy or pandas provide:

def createBoard(self):
    return np.tile(' ', (7, 7))

The disadvantage is that you will need to install numpy, because there's nothing in the standard library that works like this. But the advantage is that you have powerful tools for dealing with arrays—a[1, 1] isn't much simpler than a[1][1], but a[:,1] to access the second column is a lot simpler than [row[1] for row in a].

like image 131
abarnert Avatar answered Oct 10 '22 01:10

abarnert