8.6. Loop For Nested¶
Loop inside a loop
Used to iterate over nested data
8.6.1. Recap¶
>>> DATA = [1, 2, 3]
>>>
>>> for obj in DATA:
... print(f'{obj=}')
obj=1
obj=2
obj=3
>>> DATA = [[1, 2, 3],
... [4, 5, 6],
... [7, 8, 9]]
>>>
>>>
>>> for obj in DATA:
... print(f'{obj=}')
obj=[1, 2, 3]
obj=[4, 5, 6]
obj=[7, 8, 9]
8.6.2. Nested Loops¶
You can have loop inside a loop:
>>> DATA = [[1, 2, 3],
... [4, 5, 6],
... [7, 8, 9]]
>>>
>>>
>>> for row in DATA:
... for value in row:
... print(f'{value}', end=' ')
... print()
1 2 3
4 5 6
7 8 9
8.6.3. List of List¶
Matrix
Suggested variable name:
row
>>> DATA = [[1, 2, 3],
... [4, 5, 6],
... [7, 8, 9]]
>>>
>>>
>>> for row in DATA:
... a = row[0]
... b = row[1]
... c = row[2]
... print(f'{a=} {b=} {c=}')
a=1 b=2 c=3
a=4 b=5 c=6
a=7 b=8 c=9
8.6.4. List of Pairs¶
>>> CREW = [
... ('commander', 'Melissa Lewis'),
... ('botanist', 'Mark Watney'),
... ('pilot', 'Rick Martinez')]
>>>
>>>
>>> for astronaut in CREW:
... role = astronaut[0]
... name = astronaut[1]
... print (f'{role=}, {name=}')
role='commander', name='Melissa Lewis'
role='botanist', name='Mark Watney'
role='pilot', name='Rick Martinez'
8.6.5. List of Threes¶
>>> CREW = [
... ('commander', 'Melissa', 'Lewis'),
... ('botanist', 'Mark', 'Watney'),
... ('pilot', 'Rick', 'Martinez')]
>>>
>>>
>>> for astronaut in CREW:
... role = astronaut[0]
... firstname = astronaut[1]
... lastname = astronaut[2]
... print (f'{role=}, {firstname=}, {lastname=}')
role='commander', firstname='Melissa', lastname='Lewis'
role='botanist', firstname='Mark', lastname='Watney'
role='pilot', firstname='Rick', lastname='Martinez'
8.6.6. List of Sequence¶
>>> DATA = [
... (5.1, 3.5, 1.4, 0.2, 'setosa'),
... (5.7, 2.8, 4.1, 1.3, 'versicolor'),
... (6.3, 2.9, 5.6, 1.8, 'virginica')]
>>>
>>>
>>> for row in DATA:
... sepal_length = row[0]
... sepal_width = row[1]
... petal_length = row[2]
... petal_width = row[3]
... species = row[4]
... total = sepal_length + sepal_width + petal_length + petal_width
... print(f'{species} -> {total}')
setosa -> 10.2
versicolor -> 13.9
virginica -> 16.599999999999998
>>> DATA = [
... (5.1, 3.5, 1.4, 0.2, 'setosa'),
... (5.7, 2.8, 4.1, 1.3, 'versicolor'),
... (6.3, 2.9, 5.6, 1.8, 'virginica')]
>>>
>>>
>>> for row in DATA:
... values = row[0:4]
... species = row[4]
... print(f'{species=}, {values=}')
species='setosa', values=(5.1, 3.5, 1.4, 0.2)
species='versicolor', values=(5.7, 2.8, 4.1, 1.3)
species='virginica', values=(6.3, 2.9, 5.6, 1.8)
8.6.7. Mixed¶
Let's analyze the following example. We received data as follows:
>>> DATA = [('Mark', 'Watney'), 'Lewis', 69, 13.37, [True, None, False]]
The desired format should be:
Mark
Watney
Lewis
69
13.37
True
None
False
How to convert DATA
to desired format?
Iterating over list
with scalar and vector values - simple loop:
>>> DATA = [('Mark', 'Watney'), 'Lewis', 69, 13.37, [True, None, False]]
>>>
>>> for current in DATA:
... print(current)
('Mark', 'Watney')
Lewis
69
13.37
[True, None, False]
Iterating over list
with scalar and vector values - nested loop:
>>> DATA = [('Mark', 'Watney'), 'Lewis', 69, 13.37, [True, None, False]]
>>>
>>>
... for current in DATA:
... for element in current:
... print(element)
Mark
Watney
W
a
t
n
e
y
Traceback (most recent call last):
TypeError: 'int' object is not iterable
Iterating over list
with scalar and vector values - smart loop:
>>> DATA = [('Mark', 'Watney'), 'Lewis', 69, 13.37, [True, None, False]]
>>>
>>> for current in DATA:
... if type(current) in (list, tuple, set):
... for inside in current:
... print(inside)
... else:
... print(current)
Mark
Watney
Lewis
69
13.37
True
None
False
8.6.8. Good Practices¶
row
- best for nested loops with sequence insideConventions for rows and columns:
row
- row (all elements)column
- current column element fromrow
sequencei
- row numberj
- column numberx
- row numbery
- column numberouter
- for outer loop elementinner
- for inner loop element
Note that
i
may interfere withi
used as loop counter
8.6.9. Use Case - 0x01¶
>>> for row in [1, 2, 3]:
... print()
...
... for column in ['A', 'B', 'C']:
... print(f'{column}{row}', end=' ')
A1 B1 C1
A2 B2 C2
A3 B3 C3
8.6.10. Assignments¶
"""
* Assignment: Loop Nested Mean
* Required: yes
* Complexity: easy
* Lines of code: 5 lines
* Time: 5 min
English:
1. Calculate mean `Sepal length` value
2. Run doctests - all must succeed
Polish:
1. Wylicz średnią wartość `Sepal length`
2. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is float, \
'Variable `result` has invalid type, should be float'
>>> result
5.911111111111111
"""
DATA = [
('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
(5.8, 2.7, 5.1, 1.9, 'virginica'),
(5.1, 3.5, 1.4, 0.2, 'setosa'),
(5.7, 2.8, 4.1, 1.3, 'versicolor'),
(6.3, 2.9, 5.6, 1.8, 'virginica'),
(6.4, 3.2, 4.5, 1.5, 'versicolor'),
(4.7, 3.2, 1.3, 0.2, 'setosa'),
(7.0, 3.2, 4.7, 1.4, 'versicolor'),
(7.6, 3.0, 6.6, 2.1, 'virginica'),
(4.6, 3.1, 1.5, 0.2, 'setosa'),
]
# Arithmetic mean from `Sepal length` column
# type: float
result = ...
"""
* Assignment: Loop Nested Unique Keys
* Required: yes
* Complexity: medium
* Lines of code: 3 lines
* Time: 8 min
English:
1. Collect unique keys from all rows in one sequence `result`
2. Run doctests - all must succeed
Polish:
1. Zbierz unikalne klucze z wszystkich wierszy w jednej sekwencji `result`
2. Uruchom doctesty - wszystkie muszą się powieść
Hints:
* `row.keys()`
* Compare solutions with :ref:`Micro-benchmarking use case`
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) in (set, list, tuple), \
'Variable `result` has invalid type, should be on of (set, list, tuple)'
>>> sorted(result)
['Petal length', 'Petal width', 'Sepal length', 'Sepal width', 'Species']
"""
DATA = [
{'Sepal length': 5.1, 'Sepal width': 3.5, 'Species': 'setosa'},
{'Petal length': 4.1, 'Petal width': 1.3, 'Species': 'versicolor'},
{'Sepal length': 6.3, 'Petal width': 1.8, 'Species': 'virginica'},
{'Sepal length': 5.0, 'Petal width': 0.2, 'Species': 'setosa'},
{'Sepal width': 2.8, 'Petal length': 4.1, 'Species': 'versicolor'},
{'Sepal width': 2.9, 'Petal width': 1.8, 'Species': 'virginica'},
]
# Unique keys from DATA dicts
# type: set[str]
result = ...
"""
* Assignment: Loop For Text
* Required: no
* Complexity: medium
* Lines of code: 14 lines
* Time: 13 min
English:
1. Given is text of the "Moon Speech" by John F. Kennedy's [1]
2. Sentences are separated by period (`.`)
3. Clean each sentence from whitespaces at the beginning and at the end
4. Words are separated by spaces
5. Print the total number in whole text:
a. adverbs (words ending with "ly")
b. sentences
c. words
d. letters
e. characters (including spaces inside sentences, but not comas `,`)
f. comas (`,`)
6. Run doctests - all must succeed
Polish:
1. Dany jest tekst przemówienia "Moon Speech" wygłoszonej
przez John F. Kennedy'ego [1]
2. Zdania oddzielone są kropkami (`.`)
3. Każde zdanie oczyść z białych znaków na początku i końcu
4. Słowa oddzielone są spacjami
5. Wypisz także ile jest łącznie w całym tekście:
a. przysłówków (słów zakończonych na "ly")
b. zdań
c. słów
d. liter
e. znaków (łącznie ze spacjami wewnątrz zdań, ale bez przecinków `,`)
f. przecinków (`,`)
6. Uruchom doctesty - wszystkie muszą się powieść
References:
[1] Kennedy, J.F. Moon Speech - Rice Stadium.
Year: 1962.
Retrieved: 2021-03-06.
URL: http://er.jsc.nasa.gov/seh/ricetalk.htm
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is dict, \
'Variable `result` has invalid type, should be dict'
>>> print(result) # doctest: +NORMALIZE_WHITESPACE
{'sentences': 7,
'words': 71,
'characters': 347,
'letters': 283,
'commas': 1,
'adverbs': 0}
"""
TEXT = """
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
"""
# Number of occurrences of each grammar object
# type: dict[str,int]
result = {
'sentences': 0,
'words': 0,
'characters': 0,
'letters': 0,
'commas': 0,
'adverbs': 0,
}