1

I am looking for a simple and efficient way to iterate on an matrix (2D array) by lines and columns. Using Python.

I have 3 2D-matrices of the same size: one containing x-coordinates, one for y-coordinates, and one containing the value for some data (temperature actually) at these coordinates.

I would like to iterate on every element of the 'data' matrix, but by keeping track of the current line and column, because I then need to look for the equivalent value in the 'x' and 'y' matrices.

To be clearer, I would write it like that in Matlab:

for i = 1:nb_line
    for j = 1:nb_column
        if data(i,j) ~= 0
            <operations using x[i,j] and y[i,j]>
        end
    end
end

In Python, I was thinking in doing it like that:

for line in data:
    for elt in line:
        if not elt == 0:
            <operations>

My problem is that I am loosing track of my current position in the array, and hence cannot call x[i,j] or y[i,j]...

What is the easiest way to do that? Thank you in advance.


EDIT: My code now looks as follows.

DATA, LAT and LON are netCDF4.variables, which kinda look like 2-D masked arrays, respectively containing a geographical parameter (temperature, elevation, whatever...), its latitude and its longitude.

I want to project this data on a regular latitude/longitude grid (for example if the spatial step dlon is 0.5 degree, the first column of my array correspond to longitude 0deg, the second longitude 0.5 deg, the third 1.0deg, etc...).

sizeLon     = (lonMax-lonMin)/dlon  
sizeLat     = (latMax-latMin)/dlat
Mp          = numpy.ma.masked_array(zeros((sizeLat,sizeLon)),mask=True)
for rows in zip(LST,LAT,LON):
    for lstVal, latVal,lonVal in zip(*rows):
        if lstVal is not numpy.ma.masked:
            lp  = round(-(latVal-latMin)/dlat)
            cp  = round((lonVal-lonMin)/dlon)
            Mp[lp,cp] = lstVal
Guiux
  • 79
  • 1
  • 10
  • 1
    What is the operation you are trying to do? Most of the time in Matlab and numpy you run a vectorized version of the function on the array, rather than iterating through the elements – YXD Apr 03 '14 at 16:10
  • I am re-projecting some geographical data. So for every single element, I have first to check if the value is not in a masked data area, and then I have to compute the position of this data point in a new matrix. So I do not think I can use vectorised functions for that. – Guiux Apr 07 '14 at 09:39
  • @Gulux is the masked data also available as a numpy array? If so could you paste an example? If you can write out a tiny example and what you are trying to achieve there is often a way to do it in a couple of lines of numpy :) See [this](http://stackoverflow.com/q/10178823/553404) and [this](http://stackoverflow.com/q/5795700/553404) for some examples of how to provide data-as-code – YXD Apr 07 '14 at 09:43
  • I added some details, and my code, in the question. But I cannot post data here. – Guiux Apr 07 '14 at 14:36

2 Answers2

2

Use the enumerate function.

For example,

>>> a = ['foo', 'bar', 'foorbar']
>>> for i, name in enumerate(a):
...     print 'item %d is %s' % (i, name)
... 
item 0 is foo
item 1 is bar
item 2 is foorbar

If you do not actually need the i, j values but only the corresponding entries in another matrix, you might want to consider just zipping the rows:

>>> b = [[1, 2], [3, 4]]
>>> x = [['foo', 'bar'], ['barFoo', 'fooBar']]
>>> for rows in zip(b, x):
...     for bval, xval in zip(*rows):
...         print 'bval: %d; xval: %s' % (bval, xval)
... 
bval: 1; xval: foo
bval: 2; xval: bar
bval: 3; xval: barFoo
bval: 4; xval: fooBar
ramcdougal
  • 2,307
  • 1
  • 13
  • 24
  • Wow, I never heard about this zip(), but it works like a charm! The execution time of my script dropped from 1-2 minutes to 12 seconds! I adopt it. Thanks. – Guiux Apr 07 '14 at 09:37
2

It sounds like what you're looking for might be enumerate(), which provides you the index of the value in the collection that you're iterating over along with the value:

for i, line in enumerate(data): for j, elt in enumerate(line): if not elt == 0: <operations>

rayashmanjr
  • 166
  • 1
  • 4