[Tutor] 'for' iteration stop problem

Steven D'Aprano steve at pearwood.info
Sun Apr 3 02:59:08 CEST 2011


Mateusz Koryciński wrote:
> I have some problem with 'for' loop in algorithm.
> Code and description for this problem could be find here:
> http://stackoverflow.com/questions/5520145/how-to-stop-iteration-when-if-statement-is-true

Other people have answered your question about exiting nested loops, but 
that's not your real problem. Your real problem is that the piece of 
code shown is unreadable and unmaintainable!

(1) Python has functions: please use them to break your code into small, 
easily understandable pieces.

(2) You have a *mess* of unreadable variable names. You have:

     w.steps w.x w.y w.world data.c data.n data.e data.s data.w data.cc

(yes, you have data.c AND data.cc!!!) plus loop variables z i j and r, 
and z is never used! How is anyone supposed to understand what this 
does? Even if you solve this problem *today*, in a week you will have 
forgotten what the code does and you won't understand it.

(3) w.steps is never used except to needlessly(?) repeat the same 
calculations over and over again.

(4) w.x and w.y at least seem to be fairly obvious, although the names 
are terrible.

(5) What are w.world and all the data.* variables? Are they "north", 
"south", "east", "west"?

(6) You give an example of some output, but you don't show the *input* 
that is used to generate that data, so it is meaningless.

(7) You seem to be re-writing the data in place. That's *usually* a 
mistake (not always, but, say, 95% of the time).

It will help if you can describe what problem you are trying to solve. 
Not the algorithm you have already chosen, but the actual problem -- 
what to you hope to do? There is probably a much better way.

But for now, let me see if I can help refactor the code. You have:

for z in range(w.steps):
     for i in range(1,w.x-1):
         for j in range(1,w.y-1):
             print (i, j)
             for r in data.c:
                 if w.world[i][j] in r:
                     print r
                     ind = data.c.index(r)
                     print ind
                     if w.world[i-1][j] in data.n[ind]:
                         if w.world[i][j+1] in data.e[ind]:
                             if w.world[i+1][j] in data.s[ind]:
                                 if w.world[i][j-1] in data.w[ind]:
                                     w.world[i][j] = data.cc[ind]



* make it a function that takes meaningfully named arguments, not just 
global variables;

* throw away the top level loop, because z never gets used -- you're 
just needlessly repeating the same calculation w.steps times;

* use helper functions to make your code more readable and to allow for 
future changes to the data structure;

* comment your code!



def get_neighbours(data, i, j):
     """Return the four nearest neighbours of data[i,j].
     Returns the north, south, east, west neighbours in that order:

     [ [ ............. ]
       [ ... . n . ... ]
       [ ... w X e ... ]
       [ ... . s . ... ]
       [ ............. ] ]

     """
     return data[i-1][j], data[i+1][j], data[i][j+1], data[i][j-1]



def match_item(item, values):
     """Given a list of lists "values", match item against the items
     in the sublists, returning the index of the first matching value
     found.

     ("values" is a terrible name, but since I don't know what the
     problem you are solving is, I can't give it a more meaningful
     name.)

     >>> match_item(42, [[1, 2, 3], [11, 23, 37, 42, 55], [100, 200]])
     (1, 3)

     """
     for i, sublist in enumerate(values):
         if item in sublist:
             return (i, sublist.index(item))
     # If we never match at all, it is an error.
     raise ValueError('item not in values')



def iterate_data(data, values, north, south, east, west):
     """Iterate over data, doing something to it, I don't know what.

     data is a 2D array of numbers.
     values is a list of lists. I don't know why.
     north, south, east, west are four lists of numbers. They must
     all have the same number of items.
     """
     assert len(north) == len(south) == len(east) == len(west)
     directions = (north, south, east, west)
     # Sorry, that is a poor, undescriptive name.

     # Skip the first and last row and column.
     for i in range(1, num_rows-1):
         for j in range(1, num_cols-1):
             cell = data[i][j]
             # Find a match with values (whatever that is!)
             x,y = match_item(cell, values)
             # Now compare that cell's neighbours.
             neighbours = get_neighbours(data, i, j)
             if any(a in b[y] for (a,b) in zip(neighbours, directions)):
                 print "Matched neighbour (now what?)"




I hope this helps.




-- 
Steven



More information about the Tutor mailing list