Download presentation
Presentation is loading. Please wait.
Published byShinta Tan Modified over 6 years ago
1
2D loops In spatial analysis, it is quite common to want to loop through 2D collections. To loop through two dimensions, nest loops: data = [ [0,1,2], [3,4,5] ] for row in data: for item in row: print (item)
2
2D loops However, it is often necessary to know the coordinates in collection space of the item you're referencing. data = [ [0,1,2], [3,4,5] ] for i in range(len(data)): for j in range(len(data[i])): print (data[i][j])
3
Nesting loops for i in range(len(data)): for j in range(len(data[i])):
print (data[i][j]) Variables re-made if a loop runs more than once. The outer loop starts, then the inner loop starts. When the inner loop has run once, it returns to the start of the inner loop, not the outer loop. It keeps doing this until run to completion (j == len(data[i]); i still zero). What do you think happens to j then, and where does the code go next?
4
Nesting loops for i in range(len(data)): for j in range(len(data[i])): print (data[i][j]) 4) j is destroyed, and the outer loop increments to i = 1. 5) The inner loop runs again, j recreated as j = 0. 6) The inner loop runs to completion. Thus, each time the outer loop runs once, the inner loop runs to completion. 7) This is repeated until the outer loop completes. 8) The code then moves on.
5
Nested loops Let’s look at i and j: i j This is exactly what we need for moving down a row at a time in our array (i) and then running across each row a space at a time (j).
6
Issues This is surely one of the neatest algorithms ever! However, it is easy to make mistakes which are avoided by directly using the target variable to access items. There are three problems with the below. Can you spot them? for i in range(len(data)): for i in range(len(data[j])): data[j][i] = 10
7
2D issues The three mistakes are classics that everyone makes, even experienced coders: for i in range(len(data)): for i in range(len(data[j])): data[j][i] = 10 len(data[j])) Looping through to the wrong dimension length. This is very common if the lengths are hard-wired in, so avoid that.
8
2D issues for i in range(len(data)): for i in range(len(data[j])): data[j][i] = 10 for i Cutting and pasting your outer loop to make your inner loop, and forgetting to change part of the variable use; here, the inner increment should be to j.
9
2D issues for i in range(len(data)): for i in range(len(data[j])): data[j][i] = 10 data[j][i] Switching the indices the wrong way round. This should be data[i][j]. With an non-square array, this will result in trying to read off one side of the array and the program will break. Worse, with a square array, your data will silently be transposed. If you get confused, run through your algorithm by hand on paper, using a 2 by 3 non- square array.
10
Print Print inserts spaces when comma separated. By default ends with a newline. But this can be overridden (best in scripts): print ("a", end=",") print ("b", end=",") print ("c") a,b,c
11
When to act for i in range(len(data)): # Line here done every outer loop for j in range(len(data[i])): # Line here done every inner loop data[i][j] = 10
12
When to act for i in range(len(data)): for j in range(len(data[i])): print (data[i][j], end=",") print ("")
13
Moving window algorithms
A prime example of why we might want the coordinates is moving window algorithms. Let's start with a simple allocation to the current item: for i in range(len(data)): for j in range(len(data[i])): data[i][j] = 10 j i The looping to dealing with 2D arrays is one of the most important structures you ever learn in any programming language. Here’s how it is done: for i in range(len(data)): for j in range(len(data[j])): data[i][j] = 10 Note that we use the collection (“data”) in the above as if it was a collection of collections. We can get the first dimension using len(data), and the length of the current collection in the second dimension using len(data[i]), where i will be some position in the first dimension. This is an extremely critical piece of code, so make sure you understand what it is doing. It might help to draw a 3 by 2 array at this stage and work through the loops to see what’s happening. Two additional comments might help: j will never reach the value len(data[i]). This makes sense when we realise that the len(data[i]) positions in the collection will be labelled from zero to len(data[i]) – 1. Remember that 10 positions would be numbered 0 to 9. It will help if you realise that the i variable will increase by one each complete run through of the j variable from zero to len(data[i]). Each time j reaches len(data[i]) – 1 it will be reset to zero and the i loop will start its next iteration. When you use this code, which you will, the most important thing is that you consistently use i and j to refer to the same dimensions throughout your code. It doesn’t matter whether you think of the first index as the rows and the second as the columns, or vice versa -- the computer doesn’t mind; however, you do have to be treat them the same way each time, or you end up transposing things. Don’t, for example, do this… for j in range(len(data[i])): data[j][i] = 10 If you make this mistake, and you’re lucky, your code will crash out and tell you that you’ve tried to fill a location in the array that doesn’t exist. If you’re unlucky it will just transpose all the values in your arrays so the rows become the columns and vice versa without telling you.
14
Variations Looping through the same positions in two collections:
for i in range(len(dataA)): for j in range(len(dataA[i])): dataA[i][j] = dataB[i][j] j i dataB dataA There are two important variations on the 2D collection loop that might be useful to know about. In the first version, if you have two collections the same size, you can use the i and j values to loop through the same positions in both, for example: for i in range(len(dataA)): for j in range(len(dataA[i])): dataA[i][j] = dataB[i][j]
15
Variations Looping through two arrays at positions relative to one array (note boundary problem): for i in range(len(dataA)): for j in range(len(dataA[i])): dataA[i][j] = dataB[i-1][j-1] j i If we imagine our collection as a table, this code sets the collection value at [i][j] to whatever the value is in the collection one cell up and left of it. As you can probably tell, this wouldn’t work if the cell was on the top or leftmost line, so we’ve put in a simple if statement to catch these boundary problems. These are both very important variants on the 2D collection loop. The former is used for comparing different datasets at a single location in a 2D space, while the latter is very important when altering a location in 2D space to reflect its surroundings. dataB dataA
16
Boundary problems Various solutions. Depends on problem context.
Wrap boundaries: Suitable for modelling abstract landscapes Only process as many cells as you can: Suitable for modelling non- abstract landscapes With finite datasets (which is most geographical data), you will come across boundary problems: how do you do the processing when you run out of data? It depends strongly on the type of problem you are dealing with – is the data so abstract that you can just wrap around and start using data from the other side of the array? Will you algorithm and processing survive a bit of data loss at the corners/edges? Or could you put up with a smaller results array (by 2 cells in each direction) if you knew that the processing has been fully done? Only process cells that can have complete processing: Suitable for image processing
17
Multiple targets If you know the number of elements in the second dimension of a 2D list or tuple, you can: data = [ [0,1], [2,3], [4,5] ] for a,b in data: print (str(a) + " " + str(b))
18
zip uses Really useful for looping through two sets of data at the same time. Here, for example, we use it to make a dictionary from two lists: a = [1,2,3,4,5] b = [10,20,30,40,50] z = zip(a,b) d = {} for t in z: d[t[0]] = t[1] print(d)
19
Builtins: Iterators 1 2 missing next(iterator[, default])
If you have any doubts about the iterator returning a value, this will return a default value at the end of the iterator. Obviously make sure it doesn't create an infinite loop. If the default isn't given, it produces a warning at the end. a = list(range(3)) it = iter(a) for i in range(5): print(next(it, "missing")) 1 2 missing The warning is a StopIteration exception. We'll deal with exceptions later.
20
Reversed(sequence) reversed(seq) Get a reverse iterator.
a = list(range(3)) ri = reversed(a) for i in ri: print(i) 2 1
21
Sorting lists a.sort() # Sorts list a. From then on, the list is sorted. b = sorted(a) # Copies list a, sorts it, and attaches the copy to b. The former is more memory efficient. The latter leaves the original unchanged and will work on tuples, as it generates a list. There are a wide variety of options for sorting, including defining the kind of sorting you want. See:
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.