Is there a difference between `board[x, y]` and `board[x][y]` in Python?

Question:

I’m working through a tutorial on GeekforGeeks website and noticed that they are checking a point in an array using board[x,y], which I’ve never seen before. I don’t think this would work, but when I run the program, everything goes as expected.

I tried running a smaller code example using their method outlined above vs the method I’m more familiar with (board[x][y]), but when I run my code, I get TypeError: list indices must be integers or slices, not tuple

My code:

board = [[1,1,1], [1,2,2], [1,2,2]]
win = 'True'

if board[1][1] == 2:
    win = 'True by normal standards'
    print(win)
if board[1, 1] == 2:
    win = 'True by weird standards'
    print(win)

print(win)

Their code:

def row_win(board, player): 
    for x in range(len(board)): 
        win = True

        for y in range(len(board)): 
            if board[x, y] != player: 
                win = False
                continue

        if win == True: 
            return(win) 
    return(win) 

Can someone explain to me why board[x,y] works, and what exactly is happening? I’ve never seen this before except to create lists, and am not grasping it conceptually.

Asked By: Broski-AC

||

Answers:

They’re able to do that since they’re using NumPy, which won’t throw an error on that.

>>> a = np.array([[1,1,1], [1,2,2], [1,2,2]])
>>> a[1,1]
2
>>> # equivalent to
>>> a = [[1,1,1], [1,2,2], [1,2,2]]
>>> a[1][1]
2
>>> 
Answered By: U12-Forward

It does not actually work in base Python (like your example). If you run your code, Python throws an exception: ‘TypeError: list indices must be integers or slices, not tuple’.

The 1, 1 passed to board is interpreted as a tuple and since board should be indexed with integers or slices, this won’t work.

However, if board were some type of array-like data structure and the developer had implemented support for indexing with tuples, this would work. An example of this is arrays in numpy.

Answered By: Grismar

The board[x, y] syntax is probably being applied onto a numpy array, which accepts this syntax in order to implement row/column indexed slicing operations. Take a look at these examples:

>>> x = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])  # creates 2D array
>>> x
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

>>> x[1]  # get second row (remember, index starts at 0)
array([4, 5, 6])

>>> x[:, 2]  # get third column
array([3, 6, 9])

>>> x[1, 2]  # get element on second row, third column
6

>>> x[1][2]  # same as before but with non-broadcasting syntax (i.e. works for lists as you are used to)
6

>>> x[1, 0:2]  # get first two elements of second row  
array([4, 5])

>>> x[0:2, 0:2]  # subsets the original array, "extracting" values from the first two columns/rows only
array([[1, 2],
       [4, 5]])

Of course, writing my_list[x, y] throws an error because x, y is actually a tuple (x, y), and regular lists can’t work with tuples as an indexing value.

Answered By: jfaccioni

Because their board is either numpy.ndarray or some type that wraps it, e.g. pandas.DataFrame board[x,y] is pandas 2D indexing, not base Python.

You should have done type(board). Or show us the lines that create and initialize board.

Also, when you say “when I run the program, everything goes as expected”, you should run in interactive mode (python -i), then you could run queries like type(board) (or in iPython/jupyter type whos to see alist of variables and their types)

Answered By: smci

That works because the object they are using (in this case numpy array) overloads the __getitem__ method. See this toy example:

class MyArray:
  def __init__(self, arr):
    self.arr = arr
  def __getitem__(self, t):
    return self.arr[t[0]][t[1]]

myarr = MyArray([[1,1,1], [1,2,2], [1,2,2]])
print(myarr[0,1])
Answered By: Ant

In python, [] is __getitem__, which can be easily rewritten.

And, 1, 2 in python will give us a tuple. yes, we don’t really need () to create a non empty tuple.

So, Numpy can do this very easily, even I can.

In [1]: 1, 1
Out[1]: (1, 1)

In [2]: type(_)
Out[2]: tuple

In [3]: a = {(1, 1): 3}

In [4]: a[1, 1]
Out[4]: 3

In [5]: a[(1, 1)]
Out[5]: 3

In [6]: class NumpyArray(list):
   ...:     def __getitem__(self, index):
   ...:         if isinstance(index, tuple) and len(index) == 2:
   ...:             return self[index[0]][index[1]]
   ...:         return super().__getitem__(index)
   ...:

In [7]: b = NumpyArray([[0, 1], [2, 3]])

In [8]: b[1, 1]
Out[8]: 3

You can use below code to try on your own iPython.

class NumpyArray(list):
    def __getitem__(self, index):
        if isinstance(index, tuple) and len(index) == 2:
            return self[index[0]][index[1]]
        return super().__getitem__(index)

b = NumpyArray([[0, 1], [2, 3]])
b[1, 1]
Answered By: LiuXiMin
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.