8. Loops and nested objects

8.1. Iterating over nested list items

DATA = [1, 2, 3]

for element in DATA:
    print(element)

# 1
# 2
# 3
DATA = [(...), (...), (...)]

for element in DATA:
    print(element)

# (...)
# (...)
# (...)
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 element in DATA:
    print(element)

# (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')

8.2. Unpacking values in loop

a, b = 'a', 0
a, b = ('a', 0)
k, v = ('a', 0)
key, value = ('a', 0)
sepal_len, sepal_wid, petal_len, petal_wid, species = (5.1, 3.5, 1.4, 0.2, 'setosa')
DATA = [
    ('a', 0),
    ('b', 1),
    ('c', 2),
]

for key, value in DATA:
    print(f'key: "{key}", value: "{value}"')

# a -> 0
# b -> 1
# c -> 2
DATA = [
    (0, 1),
    ('name', 'José'),
    ('locations', ['CapeCanaveral', 'Houston']),
]

for key, value in DATA:
    print(f'{key} -> {value}')

# 0 -> 1
# name -> José
# locations -> ['CapeCanaveral', 'Houston']
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'),
]

# sepal_len, sepal_wid, petal_len, petal_wid, species = (5.1, 3.5, 1.4, 0.2, 'setosa')

for sepal_len, sepal_wid, petal_len, petal_wid, species in DATA:
    print(species)

# setosa
# versicolor
# virginica

8.3. Enumerating and item index

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'),
]

i = 0

for element in DATA:
    print(f'{i} -> {element}')
    i += 1

# 0 -> (5.1, 3.5, 1.4, 0.2, 'setosa')
# 1 -> (5.7, 2.8, 4.1, 1.3, 'versicolor')
# 2 -> (6.3, 2.9, 5.6, 1.8, 'virginica')
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 i, element in enumerate(DATA):
    print(f'{i} -> {element}')

# 0 -> (5.1, 3.5, 1.4, 0.2, 'setosa')
# 1 -> (5.7, 2.8, 4.1, 1.3, 'versicolor')
# 2 -> (6.3, 2.9, 5.6, 1.8, 'virginica')

8.4. Iterating over dict items

  • dict elements order changes!

8.4.1. Iterating over dict values

DATA = {
    'Sepal length': 5.1,
    'Sepal width': 3.5,
    'Petal length': 1.4,
    'Petal width': 0.2,
    'Species': 'setosa',
}

DATA.values()
# [5.1, 3.5, 1.4, 0.2, 'setosa']

for element in DATA.values():
    print(element)

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

8.4.2. Iterating over dict keys

DATA = {
    'Sepal length': 5.1,
    'Sepal width': 3.5,
    'Petal length': 1.4,
    'Petal width': 0.2,
    'Species': 'setosa',
}

DATA.keys()
# ['Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species']

for element in DATA.keys():
    print(element)

# 'Sepal length'
# 'Sepal width'
# 'Petal length'
# 'Petal width'
# 'Species'

8.4.3. By default dict iterates over keys

DATA = {
    'Sepal length': 5.1,
    'Sepal width': 3.5,
    'Petal length': 1.4,
    'Petal width': 0.2,
    'Species': 'setosa',
}

for element in DATA:
    print(element)

# 'Sepal length'
# 'Sepal width'
# 'Petal length'
# 'Petal width'
# 'Species'

8.4.4. Getting pair: key, value from dict items

DATA = {
    'Sepal length': 5.1,
    'Sepal width': 3.5,
    'Petal length': 1.4,
    'Petal width': 0.2,
    'Species': 'setosa',
}

DATA.items()
# [
#   ('Sepal length', 5.1),
#   ('Sepal width', 3.5),
#   ('Petal length', 1.4),
#   ('Petal width', 0.2),
#   ('Species', 'setosa')
# ]


for key, value in DATA.items():
    print(f'{key} -> {value}')

# Sepal length -> 5.1
# Sepal width -> 3.5
# Petal length -> 1.4
# Petal width -> 0.2
# Species -> setosa

8.4.5. list of dict

DATA = [
    {'Sepal length': 5.1, 'Sepal width': 3.5, 'Petal length': 1.4, 'Petal width': 0.2, 'Species': 'setosa'},
    {'Sepal length': 5.7, 'Sepal width': 2.8, 'Petal length': 4.1, 'Petal width': 1.3, 'Species': 'versicolor'},
    {'Sepal length': 6.3, 'Sepal width': 2.9, 'Petal length': 5.6, 'Petal width': 1.8, 'Species': 'virginica'},
]

for row in DATA:
    print(row['Species'])

# setosa
# versicolor
# virginica

8.5. Iterating complex types

DATA = ['Max', ('1.0', 'José'), 3, 2.8, {True, None, False}]

for element in DATA:
    print(f'value: "{element}"')

# value: "Max"
# value: "('1.0', 'José')"
# value: "3"
# value: "2.8"
# value: "{False, True, None}"
DATA = ['Max', ('1.0', 'José'), 3, 2.8, {True, None, False}]

for element in DATA:
    for sub in element:
        print(f'value: "{sub}"')

# value: "M"
# value: "a"
# value: "x"
# value: "1.0"
# value: "José"
# TypeError: 'int' object is not iterable
DATA = ['Max', ('1.0', 'José'), 3, 2.8, {True, None, False}]

for element in DATA:

    if isinstance(element, (list, set, tuple)):
        for sub in element:
            print(f'value: "{sub}"')
    else:
        print(f'value: "{element}"')

# value: "Max"
# value: "1.0"
# value: "José"
# value: "3"
# value: "2.8"
# value: "False"
# value: "True"
# value: "None"

8.6. Assignments

8.6.1. Unique keys from schema-less database

  • Filename: loop_unique_keys.py
  • Lines of code to write: 5 lines
  • Estimated time of completion: 5 min
  1. Mając bazę danych z listingu poniżej
  2. Iteruj po rekordach w bazie danych
  3. Z rekordu wyciągnij klucze
  4. Wygeneruj listę unikalnych kluczy
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'},
    {'Petal length': 1.4, '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'},
]
The whys and wherefores:
 
  • Generowanie zbiorów
  • Usuwanie powtarzających się elementów
  • Wyciąganie elementów ze słownika
  • Iterowanie po słowniku
  • Aktualizacja zbiorów

8.6.2. Label encoder

  • Filename: loop_label_encoder.py
  • Lines of code to write: 13 lines
  • Estimated time of completion: 15 min
  1. Dany jest zbiór pomiarów Irysów Code Listing 8.1.

  2. Ze zbioru wyodrębnij dane odrzucając nagłówek

  3. Z danych wyodrębnij:

    • cechy opisujące: features: List[Tuple[float]]
    • cechy opisywane: labels: List[int]
  4. Przykład danych wyodrębnionych:

    features = [
        (5.8, 2.7, 5.1, 1.9),
        (5.1, 3.5, 1.4, 0.2),
        (5.7, 2.8, 4.1, 1.3),
        (6.3, 2.9, 5.6, 1.8),
        (6.4, 3.2, 4.5, 1.5),
        (4.7, 3.2, 1.3, 0.2), ...]
    
    labels = [0, 1, 2, 1, 2, 0, ...]
    
  5. Aby móc odszyfrować labels i zamienić wartości na nazwy gatunków, potrzebny jest słownik podmiany “liczba -> nazwa”

  6. Wygeneruj słownik species: Dict[int, str] na podstawie danych

  7. Przykład słownika species:

    species = {
        0: 'virginica',
        1: 'setosa',
        2: 'versicolor'
    }
    
  8. Wyświetl na ekranie:

    • species
    • labels
    • features
Algorithm:
  1. Wyodrębnij dane odrzucając nagłówek
  2. Stwórz słownik gatunków species
  3. Iteruj po elementach zbioru danych
  4. Gatunek to ostatni element rekordu
  5. Jeżeli w słowniku nie ma gatunku, to dodaj go z kolejnym numerem
  6. Do listy label dodawaj wartość słownika gatunków dla gatunku w tym rekordzie
  7. Odwróć słownik gatunków
  8. Wyświetl na ekranie species oraz labels
The whys and wherefores:
 
  • Sprawdzanie występowania elementów w słowniku
  • Generowanie słownika i listy na podstawie innych danych
  • Odwracanie słownika
Code Listing 8.1. Sample Iris databases
[
    ('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.9, 3.0, 1.4, 0.2, 'setosa'),
    (4.9, 2.5, 4.5, 1.7, 'virginica'),
    (7.1, 3.0, 5.9, 2.1, 'virginica'),
    (4.6, 3.4, 1.4, 0.3, 'setosa'),
    (5.4, 3.9, 1.7, 0.4, 'setosa'),
    (5.7, 2.8, 4.5, 1.3, 'versicolor'),
    (5.0, 3.6, 1.4, 0.3, 'setosa'),
    (5.5, 2.3, 4.0, 1.3, 'versicolor'),
    (6.5, 3.0, 5.8, 2.2, 'virginica'),
    (6.5, 2.8, 4.6, 1.5, 'versicolor'),
    (6.3, 3.3, 6.0, 2.5, 'virginica'),
    (6.9, 3.1, 4.9, 1.5, 'versicolor'),
    (4.6, 3.1, 1.5, 0.2, 'setosa'),
]