5. for loop

5.1. Syntax

5.1.1. No context syntax

Listing 5.2. for loop syntax
for ... in ... :
    ...

5.1.2. Generic syntax

Listing 5.3. for loop generic syntax
for my_variable in ITERATOR:
    print(my_variable)

5.1.3. Example

Listing 5.4. for loop syntax: printing each number from list
DATA = ['a', 'b', 'c']

for number in DATA:
    print(number)

# 'a'
# 'b'
# 'c'
Listing 5.5. for loop syntax: data can be inline
for number in ['a', 'b', 'c']:
    print(number)

# 'a'
# 'b'
# 'c'

5.2. Iterating over str

  • Iterating str will get character on each iteration

Listing 5.6. Iterating over str
for character in 'setosa':
    print(character)

# s
# e
# t
# o
# s
# a

5.3. Iterating simple collections

5.3.1. Iterating over list

Listing 5.7. Iterating over list
DATA = [5.1, 3.5, 1.4, 0.2, 'setosa']

for element in DATA:
    print(element)

# 5.1
# 3.5
# 1.4
# 0.2
# 'setosa'

5.3.2. Iterating over tuple

Listing 5.8. Iterating over tuple
DATA = (5.1, 3.5, 1.4, 0.2, 'setosa')

for element in DATA:
    print(element)

# 5.1
# 3.5
# 1.4
# 0.2
# 'setosa'

5.3.3. Iterating over set

Listing 5.9. Iterating over set
DATA = {5.1, 3.5, 1.4, 0.2, 'setosa'}

for element in DATA:
    print(element)

# 5.1
# 3.5
# 1.4
# 0.2
# 'setosa'

5.4. Working with Generators and Iterators

5.4.1. Loops with range

  • range(start, stop, step)

  • range().start is inclusive

  • range().stop is exclusive

  • range().step can be defined

  • range(0, 3) will generate (0, 1, 2)

Listing 5.10. Loops with range
for number in range(0, 3):
    print(number)

# 0
# 1
# 2
Listing 5.11. Loops with range
for number in range(4, 11, 2):
    print(number)

# 4
# 6
# 8
# 10

5.4.2. enumerate

  • Pythonic way

  • Preferred over i=0 and i+=1 for every iteration

  • enumerate() will return counter and value for every iteration

Listing 5.12. enumerate() will return counter and value for every iteration
DATA = ['a', 'b', 'c']

for i, letter in enumerate(DATA):
    print(f'{i} -> {letter}')

# 0 -> a
# 1 -> b
# 2 -> c
Listing 5.13. enumerate() can start with custom number
DATA = ['a', 'b', 'c']

for i, letter in enumerate(DATA, start=5):
    print(f'{i}, {letter}')

# 5 -> a
# 6 -> b
# 7 -> c

5.5. Bad practice

5.5.1. range(len())

  • Very common bad practice

  • poor variable naming and readability

  • range(len(...)) will evaluate generator to calculate length

  • DATA[i] lookups has O(n) complexity!!

  • Does not use generator at all!

Listing 5.14. Bad practice
DATA = ['a', 'b', 'c']

for i in range(len(DATA)):
    print(DATA[i])

# a
# b
# c
Listing 5.15. Better solution
DATA = ['a', 'b', 'c']

for letter in DATA:
    print(letter)

# a
# b
# c

5.6. Example

5.6.1. Create dict from two list

Listing 5.16. Create dict from two list
keys = ['a', 'b', 'c', 'd']
values = [1, 2, 3, 4]
output = {}

for i, element in enumerate(keys):
    key = keys[i]
    value = values[i]
    output[key] = value

print(output)
# {
#     'a': 1,
#     'b': 2,
#     'c': 3,
#     'd': 4,
# }

5.7. else

  • else will execute, if break was not used to exit the loop

DATA = """
127.0.0.1       localhost
127.0.0.1       astromatt
10.13.37.1      nasa.gov esa.int roscosmos.ru
255.255.255.255 broadcasthost
::1             localhost
"""
hostnames = []

for line in DATA.splitlines():
    if not line:
        continue

    ip, *hosts = line.split()
    # line.split() == ['10.13.37.1', 'nasa.gov', 'esa.int', 'roscosmos.ru']
    # ip == '10.13.37.1'
    # hosts == ['nasa.gov', 'esa.int', 'roscosmos.ru']

    for record in hostnames:
        if record['ip'] == ip:
            record['hostnames'].update(hosts)
            break
    else:
        hostnames.append({
            'hostnames': set(hosts),
            'ip': ip,
        })

print(hostnames)
# [
#   {'ip': '127.0.0.1', 'hostnames': {'astromatt', 'localhost'}},
#   {'ip': '10.13.37.1', 'hostnames': {'roscosmos.ru', 'esa.int', 'nasa.gov'}},
#   {'ip': '255.255.255.255', 'hostnames': {'broadcasthost'}},
#   {'ip': '::1', 'hostnames': {'localhost'}},
# ]

5.8. Assignments

5.8.1. Counter

  • Filename: for_counter.py

  • Lines of code to write: 5 lines

  • Estimated time of completion: 5 min

  1. Dane są liczby na listingu Listing 5.17.

  2. Policz ile jest wystąpień każdej z cyfr w tej liście

  3. Zwróć counter: Dict[int, int]

    • klucz - cyfra

    • wartość - ilość wystąpień

The whys and wherefores
  • Definiowanie i korzystanie z dict z wartościami

  • Iterowanie po liście

Listing 5.17. Numbers for dict counter
[1, 4, 6, 7, 4, 4, 4, 5, 1, 7, 0,
 0, 6, 5, 0, 0, 9, 7, 0, 4, 4, 8,
 2, 4, 0, 0, 1, 9, 1, 7, 8, 8, 9,
 1, 3, 5, 6, 8, 2, 8, 1, 3, 9, 5,
 4, 8, 1, 9, 6, 3]

5.8.2. Digit Segmentation

  • Filename: for_segmentation.py

  • Lines of code to write: 12 lines

  • Estimated time of completion: 10 min

  1. Dane są liczby na listingu Listing 5.18.

  2. Policz ile jest wystąpień każdej z grup w tej liście

    • grupa cyfr małe: cyfry z przedziału [0-2]

    • grupa cyfr średnie: cyfry z przedziału [3-7]

    • grupa cyfr duże: cyfry z przedziału [8-9]

  3. Zwróć counter: Dict[str, int]

    • klucz - grupa

    • wartość - ilość wystąpień

The whys and wherefores
  • Definiowanie i korzystanie z dict z wartościami

  • Iterowanie po liście

Listing 5.18. Numbers for dict counter
[1, 4, 6, 7, 4, 4, 4, 5, 1, 7, 0,
 0, 6, 5, 0, 0, 9, 7, 0, 4, 4, 8,
 2, 4, 0, 0, 1, 9, 1, 7, 8, 8, 9,
 1, 3, 5, 6, 8, 2, 8, 1, 3, 9, 5,
 4, 8, 1, 9, 6, 3]

5.8.3. Get elements from nested data structure

  • Filename: for_nested.py

  • Lines of code to write: 3 lines

  • Estimated time of completion: 10 min

  1. Na podstawie DATA z Listing 5.19.

  2. Po odrzuceniu nagłówka iteruj po danych

  3. Wyświetl na ekranie nazwy gatunków zaczynające się na “v”.

Listing 5.19. Iris sample dataset
DATA = [
    ('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
    (5.8, 2.7, 5.1, 1.9, {'species': 'virginica'}),
    (5.1, 3.5, 1.4, 0.2, {'species': 'setosa'}),
    (5.7, 2.8, 4.1, 1.3, {'species': 'versicolor'}),
    (6.3, 2.9, 5.6, 1.8, {'species': 'virginica'}),
    (6.4, 3.2, 4.5, 1.5, {'species': 'versicolor'}),
    (4.7, 3.2, 1.3, 0.2, {'species': 'setosa'}),
    (7.0, 3.2, 4.7, 1.4, {'species': 'versicolor'}),
    (7.6, 3.0, 6.6, 2.1, {'species': 'virginica'}),
    (4.6, 3.1, 1.5, 0.2, {'species': 'setosa'}),
]

5.8.4. Text analysis

  • Filename: for_text_analysis.py

  • Lines of code to write: 10 lines

  • Estimated time of completion: 10 min

  1. Dany jest tekst przemówienia John F. Kennedy’ego “Moon Speech” wygłoszony na Rice Stadium Listing 5.20.

  2. Zdania oddzielone są kropkami

  3. Każde zdanie oczyść z białych znaków na początku i końcu

  4. Wyrazy oddzielone są spacjami

  5. Policz ile jest wyrazów w każdym zdaniu

  6. Wypisz na ekranie słownik o strukturze:

    • Dict[str, int]

    • klucz: zdanie

    • wartość: ilość wyrazów

  7. Na końcu wypisz także ile jest łącznie w całym tekście:

    • przysłówków (słów zakończonych na “ly”)

    • zdań

    • słów

    • znaków (łącznie ze spacjami wewnątrz zdań, ale bez kropek)

The whys and wherefores
  • Dzielenie stringów

  • Sprawdzanie długości ciągów znaków

  • Iterowanie po elementach listy

  • Nazywanie zmiennych

Listing 5.20. “Moon Speech” by John F. Kennedy, Rice Stadium, Houston, TX, 1962-09-12 [Ken62]
We choose to go to the Moon. We choose to go to the Moon in this decade and do the other things. Not because they are easy, but because they are hard. Because that goal will serve to organize and measure the best of our energies and skills. Because that challenge is one that we are willing to accept. One we are unwilling to postpone. And one we intend to win