In the last lecture we learned that Python has objects that come from 4 basic iterator types, which are the string, list, tuple, and dict types, and they can all be used in for loops.
In this lecture we look at commonly used working for-loop patterns over those object types. We also consider some problem for-loop anti-patterns, which should be avoided. Again, these patterns work for any object from the fantastic-four iterator types. Now let us call one such object items.
The counting pattern
The counting pattern is used to count the number of items. Note that the built-in function len already does. But is is useful to see how to count each single item i in our iterable items.
count = 0 for i in items: count = count + 1 print "There are", count, "items."
The filtered-count pattern
A variation on the counting pattern involves filtering. When filtering, we use an if statement to decide whether we should count an item or not. Suppose we wish to count the number of times an item z is in the set of items:
z-count = 0 for i in items: if (i == z): z-count = z-count + 1 print "There are", z-count, "items equal to z."
Of course this is a pattern, and we could replace the if test (i==z) with any predicate test – that is code that returns True or False.
The reduce or accumulate pattern
Suppose it makes sense that the items can be added added all together. That process is called reduction or accumulation and has a simple pattern:
total = 0 # start an accumulation at the identity for i in items: total = total + i print "The total is", total
For this pattern, we could replace the summation (+) with any
binary operation; for example, multiplication (*), the min or the max function.
The filtered-reduction pattern
Let us simply compose the two patterns:
total = 0 for i in items: if (i == z) z-total = z-total + i print "The z-total in items is", z-total
The extreme pattern
Suppose we wish to find the most extreme value of an item in the set, usually the largest or smallest value. Here is an approach in which we use a variable largest (or largest-so-far) that assumes the first item is the largest and then corrects that assumption with each iteration.
largest = items for i in items: if (i > largest): largest = i print "The largest item is", largest
The extreme-index pattern
We often wish to determine a pointer (or index) of the most extreme value in a set of items, rather than the actual extreme value itself. In lists, tuples, strings (and later arrays) this pointer is simply a number between 0 and the length of set of items. As above, we will assume the first item (index zero) holds the extreme value, and iterate to correct that assumption:
l-index = 0 largest = items for idx in range(len(items): if (items[idx] > largest): largest = items[idx] l-index = idx print "The index of the largest item is", l-index
The filter or extract pattern
A special case of a filtered-accumulation is called simply a filter. Instead of summing the filtered items (for example), we collect the filtered items into a new list. The new list is said to be a filter or an extract of the original. Here we assume we have previously written a predicate test function.
new =  # creates a new empty list for i in items: if test(i): new.append(i)
The mutated loop Anti-pattern
One common error is to modify or mutate the items in the middle of the loop. For example.
for i in items: if test(i): items.remove(i)
This can produce highly unexpected results and should be avoided.