Catherine Georgia
Catherine Georgia

Reputation: 969

How to wrap around to the start/end of a list?

I have a 2d array with a different species in each one. I pick a random element on the array and I want to count up how many of each species are in the eight squares immediately adjacent to that element.

But I want the array to wrap at the edges, so if I pick an element on the top row, the bottom row will be counted as "adjacent". How can I do this while iterating through j in range (x-1,x+1) and the same for j and y?

Also, is there a more elegant way of omitting the element I originally picked while looking through the adjacent squares than the if (j!=x or k!=y line?

numspec = [0] * len(allspec)
for i in range (0,len(allspec)):
    #count up how many of species i there is in the immediate area
    for j in range(x-1,x+1):
        for k in range(y-1,y+1):
            if (j!=x or k!=y):
                numspec[hab[i][j]] = numspec[hab[i][j]]+1

Upvotes: 0

Views: 7055

Answers (3)

Jan Spurny
Jan Spurny

Reputation: 5537

As for wrapping, I would recomend using relative indexing from -1 to +1 and then computing real index using modulo operator (%).

As for making sure you don't count the original element (x, y), you are doing just fine (I would probably use reversed contidion and continue, but it doesn't matter).

I don't quite understand your usage of i, j, k indexes, so I'll just assume that i is index of the species, j, k are indexes into the 2d map called hab which I changed to x_rel, y_rel and x_idx and y_idx to make it more readable. If I'm mistaken, change the code or let me know.

I also took the liberty of doing some minor fixes:

  • introduced N constant representing number of species
  • changed range to xrange (xrange is faster, uses less memory, etc)
  • no need to specify 0 in range (or xrange)
  • instead of X = X + 1 for increasing value, I used += increment operator like this: X += 1

Here is resulting code:

N = len(allspec)
numspec = [0] * N
for i in xrange(N):
    for x_rel in xrange(-1, +1):
        for y_rel in xrange(-1, +1):
            x_idx = (x + xrel) % N
            y_idx = (y + yrel) % N
            if x_idx != x or y_idx != y:
                numspec[hab[x_idx][y_idx]] += 1

Upvotes: 1

Sheena
Sheena

Reputation: 16242

You could construct a list of the adjacent elements and go from there. For example if your 2d list is called my_array and you wanted to examine the blocks immediately surrounding my_array[x][y] then you can do something like this:

xmax = len(my_array)
ymax = len(my_array[0])  #assuming it's a square...

x_vals = [i%xmax for i in [x-1,x,x+1]]
y_vals = [blah]

surrounding_blocks = [ 
     my_array[x_vals[0]][y_vals[0]],
     my_array[x_vals[0]][y_vals[1]],
     my_array[x_vals[0]][y_vals[2]],
     my_array[x_vals[2]][y_vals[0]],
     my_array[x_vals[2]][y_vals[1]],
     my_array[x_vals[2]][y_vals[2]],
     my_array[x_vals[1]][y_vals[0]],
     my_array[x_vals[1]][y_vals[2]],
        ] 

Upvotes: 0

f p
f p

Reputation: 3223

You can wrap using j%8 that gives you a number from 0 to 7.

Upvotes: 2

Related Questions