Mark Ransom
Mark Ransom

Reputation: 308111

How do you do two dimensional (x,y) indexing in Python?

Generally if you have a two dimensional data structure, it's a combination of two containers - a list of lists, or a dictionary of dictionaries. What if you want to make a single collection but work it in two dimensions?

Instead of:

collection[y][x]

do:

collection[x,y]

I know it's possible, because the PIL Image.load function returns an object that works this way.

Upvotes: 5

Views: 4763

Answers (3)

Octipi
Octipi

Reputation: 831

I found this recipe at the python mailing list. With it you can access the elements of a container using an iterator of indexes. If you need to use container[index_1, index_2] notation, this can be adapted easily using the methods outlined by Mark's post.

>>> from operator import getitem
>>> from functools import reduce
>>> l = [1,[2,[3,4]]]
>>> print(reduce(getitem, [1,1,1], l))
 4

Here is a different approach suggested on the python mailing list that I adapted to container[index_1, index_2] notation.

class FlatIndex(object):
  def __init__(self, l):
    self.l = l
  def __getitem__(self, key):
    def nested(l, indexes):
      if len(indexes) == 1:
        return l[indexes[0]]
      else:
        return nested(l[indexes[0]], indexes[1:])
    return nested(self.l, key)

>>> l = [1,[2,[3,4,[5,6]]]] 
>>> a = FlatIndex(l)
>>> print(a[1,1,2,1])
 6

Upvotes: 0

mpenkov
mpenkov

Reputation: 21896

Use numpy arrays.

If you have an ordinary Python array, you can turn it into a numpy array and access its elements like you described:

a = [[1,2,3],[4,5,6],[7,8,9]]
A = numpy.array(a)
print A[1,1]

will print:

5

Another example:

A = numpy.zeros((3, 3))
for i in range(3):
    for j in range(3):
        A[i,j] = i*j
print A

will give you:

[[ 0.  0.  0.]
 [ 0.  1.  2.]
 [ 0.  2.  4.]]

Upvotes: 1

Mark Ransom
Mark Ransom

Reputation: 308111

The key is to understand how Python does indexing - it calls the __getitem__ method of an object when you try to index it with square brackets []. Thanks to this answer for pointing me in the right direction: Create a python object that can be accessed with square brackets

When you use a pair of indexes in the square brackets, the __getitem__ method is called with a tuple for the key parameter.

Here's a simple demo class that simply returns an integer index into a one dimension list when given a two dimension index.

class xy(object):

    def __init__(self, width):
        self._width = width

    def __getitem__(self, key):
        return key[1] * self._width + key[0]

>>> test = xy(100)
>>> test[1, 2]
201
>>> test[22, 33]
3322

There's also a companion __setitem__ method that is used when assigning to an index in square brackets.

Upvotes: 10

Related Questions