Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Loop Details
#4
Now, I noted the connection between the range function and list slicing. Lots of people notice that, and that leads them to iterate over lists like this:

primes = [2, 3, 5, 7, 11, 13, 17]
for prime_index in range(len(primes)):
    square = prime[prime_index] ** 2
    print(f'The square of {prime[prime_index]} is {square}.')
This is also common among programmers familiar with other languages, as it is a common way to loop over lists or arrays or whatever other languages call them. However, in Python it is wasteful. We don't care what index the prime is in the list, we just care about the prime an it's square. Python gives us a way to get the primes without the indexes:

primes = [2, 3, 5, 7, 11, 13, 17]
for prime in primes:
    square = prime ** 2
    print(f'The square of {prime} is {square}.')
Now we have simpler code with the exact same result. Simple is good. But how does it work? Lists can be iterators, just like the range function. As iterators (actually, converted to iterators) they assign one item at a time to the looping variable from the list, in order. So we get the primes without having to worry about their index.

But maybe we do want the index. Should we go back to using range? No, we should use the enumerate function:

primes = [2, 3, 5, 7, 11, 13, 17]
for prime_index, prime in enumerate(primes):
    square = prime ** 2
    print(f'The square of prime #{prime_index + 1} is {square}.')
The enumerate function works as an iterator, but it applies to another iterator, in this case the primes list. It returns tuples of the index of the item and the item. That's why we have two loop variables in the above for loop. (If you are not familiar with tuple assignment in Python, look it up.)

We had to add one above to change the index starting at zero to an index starting at one. We can get around that with the start parameter to enumerate:

primes = [2, 3, 5, 7, 11, 13, 17]
for prime_index, prime in enumerate(primes, start = 1):
    square = prime ** 2
    print(f'The square of prime #{prime_index} is {square}.')
It's more typing in this case, but it can be less typing, and I think it's clearer. Clear is even more important than simple, although simple also helps clarity.

Another common use of looping with indexes is to loop over two lists at the same time, like so:

primes = [2, 3, 5, 7, 11, 13, 17]
fibs = [1, 1, 2, 3, 5, 8, 13]
for index in range(len(primes)):
    print(primes[index] + fibs[index])
Note that if fibs is shorter than primes, you will get an index error here. We could correct for that with a call to min(), but there is an easier way that avoids indexing: the zip function. The zip function takes two or more lists and "zips" them together. First it returns a tuple of the first item in each list, then a tuple of the second item in each list, and so on. So if you have nums = [1, 2, 3] and chars = ['A', 'B', 'C'], then zip(nums, chars) gives you (1, 'a'), then (2, 'b'), then (3, 'c'). As a bonus, it automatically stops when the shortest list runs out. So our loop becomes:

primes = [2, 3, 5, 7, 11, 13, 17]
fibs = [1, 1, 2, 3, 5, 8, 13]
for prime, fib in zip(primes, fibs):
    print(prime + fib)
And what do you know: it's simpler.

Yet another common use of index loops is to loop over sequential pairs of items in a list:

primes = [2, 3, 5, 7, 11, 13, 17]
for prime_index in range(len(primes) - 1):
    print(primes[prime_index] * primes[prime_index + 1])
This gives us the products of the consecutive primes. This gets a bit more complicated that going over two lists at once. We have to subtract one to avoid going over the end of the list with the second item, and add one to get to the second item. We can do this with zip by zipping the list to itself without the first item:

primes = [2, 3, 5, 7, 11, 13, 17]
for first, second in zip(primes, primes[1:]):
    print(first * second)
Here we take advantage of zip stopping when the shortest list runs out. That way we don't have to subtract an item from the range to account for an addition elsewhere.

Just as Python gives a clean, simple way to loop over lists, we can also loop over other containers:
  • Looping over a string gives you the characters of the string.
  • Looping over tuples is just like looping over a list.
  • Looping over dictionaries loops over the keys of the dictionary.
    • You can loop over the values of a dictionary with some_dict.values()
    • You can loop over the (key, value) pairs of a dictionary with some_dict.items()
  • Looping over files loops over the lines of the files.

I often find myself wanting strings to loop over the words in the string, but that is easy to do with for word in text.split():.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply


Messages In This Thread
Loop Details - by ichabod801 - Sep-13-2019, 06:41 PM
RE: Loop Details - by ichabod801 - Sep-13-2019, 06:42 PM
RE: Loop Details - by ichabod801 - Sep-13-2019, 06:43 PM
RE: Loop Details - by ichabod801 - Sep-13-2019, 06:44 PM
RE: Loop Details - by ichabod801 - Sep-13-2019, 06:47 PM
RE: Loop Details - by ichabod801 - Sep-13-2019, 06:49 PM

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020