12.6. For Recap

12.6.1. About

  • Iterating works for builtin sequences

  • Works with: str, bytes, list, tuple, set, dict

  • Naming Current Element: letter, digit, number, user, color, sentence

Iterating Str:

>>> DATA = 'abc'
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating Tuple:

>>> DATA = ('a', 'b', 'c')
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating List:

>>> DATA = ['a', 'b', 'c']
>>>
>>> for x in DATA:
...     print(x)
a
b
c

Iterating Set:

>>> DATA = {'a', 'b', 'c'}
>>>
>>> for x in sorted(DATA):
...     print(x)
a
b
c

12.6.2. Nested

  • Loop inside a loop

  • Used to iterate over nested data

  • Iterating List of List

  • Iterating List of Pairs

  • Iterating List of Sequence

  • Iterating List of Dicts

  • Iterating Mixed

List of List:

>>> DATA = [[1, 2, 3],
...         [4, 5, 6],
...         [7, 8, 9]]
>>>
>>>
>>> for row in DATA:
...     for value in row:
...         print(value)
1
2
3
4
5
6
7
8
9

List of Pairs:

>>> users = [
...     ('Alice', 'Apricot'),
...     ('Bob', 'Banana'),
...     ('Carol', 'Corn'),
... ]
>>>
>>> for user in users:
...     firstname = user[0]
...     lastname = user[1]
...     print(f'{firstname=}, {lastname=}')
firstname='Alice', lastname='Apricot'
firstname='Bob', lastname='Banana'
firstname='Carol', lastname='Corn'

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:
...     values = row[0:4]
...     species = row[4]
...     print(f'{values=}, {species=}')
values=(5.1, 3.5, 1.4, 0.2), species='setosa'
values=(5.7, 2.8, 4.1, 1.3), species='versicolor'
values=(6.3, 2.9, 5.6, 1.8), species='virginica'

List of Dicts:

>>> DATA = [
...     {'firstname': 'Alice', 'lastname': 'Apricot'},
...     {'firstname': 'Bob', 'lastname': 'Banana'},
...     {'firstname': 'Carol', 'lastname': 'Corn'},
... ]
>>>
>>> for row in DATA:
...     firstname = row['firstname']
...     lastname = row['lastname']
...     print(f'{firstname=}, {lastname=}')
firstname='Alice', lastname='Apricot'
firstname='Bob', lastname='Banana'
firstname='Carol', lastname='Corn'

Mixed:

>>> DATA = ['Alice', 'Apricot', ('alice@example.com', 'alice@example.edu'), 30]
>>>
>>> for item in DATA:
...     if type(item) in (tuple, list):
...         for x in item:
...             print(x)
...     else:
...         print(item)
Alice
Apricot
alice@example.com
alice@example.edu
30

12.6.3. For Unpack

  • Unpacking: a, b = 1, 2

  • Instead for row in data you can unpack for a, b in data

  • Unpack List of Tuples

>>> USERS = [
...     ('alice', 'secret'),
...     ('bob', 'qwerty'),
...     ('carol', '123456'),
... ]
>>>
>>> for username, password in USERS:
...     print(f'{username=}, {password=}')
...
username='alice', password='secret'
username='bob', password='qwerty'
username='carol', password='123456'

12.6.4. For Patterns

  • Range - when you need a sequential number

  • Range of Length - when you need: index

  • Enumerate - when you need: index and element

  • Zip - when you need elements at the same index from both A and B sequences

Range:

>>> for x in range(3):
...     print(x)
...
0
1
2

Range of Length:

>>> users = ['alice', 'bob', 'carol']
>>>
>>> for i in range(len(users)):
...     user = users[i]
...     print(user)
...
alice
bob
carol

Enumerate:

>>> users = ['alice', 'bob', 'carol']
>>> i = 0
>>>
>>> for user in users:
...     print(f'{i=}, {user=}')
...     i += 1
...
i=0, user='alice'
i=1, user='bob'
i=2, user='carol'

Zip:

>>> dataA = ['Alice', 'Bob', 'Carol']
>>> dataB = ['Apricot', 'Banana', 'Corn']
>>>
>>> times = min(len(dataA), len(dataB))  # 3
>>>
>>> for i in range(times):  # for i in range(3)
...     a = dataA[i]
...     b = dataB[i]
...     print(f'{a=}, {b=}')
...
a='Alice', b='Apricot'
a='Bob', b='Banana'
a='Carol', b='Corn'

12.6.5. For Dict

  • Iterate Keys

  • Iterate Values

  • Iterate Items - key-value pairs

  • By default dict iterates over keys

  • Iterate Keys

  • Iterate Values

  • Iterate Items - key-value pairs

  • By default dict iterates over keys

>>> data = {'firstname': 'Alice', 'lastname': 'Apricot'}

Keys

>>> for key in data.keys():
...     print(f'{key=}')
key='firstname'
key='lastname'

Values:

>>> for value in data.values():
...     print(f'{value=}')
value='Alice'
value='Apricot'

Items (key-value pair):

>>> for item in data.items():
...     print(f'{item=}')
item=('firstname', 'Alice')
item=('lastname', 'Apricot')

Default:

>>> for default in data:
...     print(f'{default=}')
default='firstname'
default='lastname'

12.6.6. Assignments

# %% About
# - Name: For Recap Split
# - Difficulty: medium
# - Lines: 5
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Separate numeric values from species names
# 2. Result assign to variables:
#    - `values: list[tuple]` - list of numeric values (ie. 5.8, 2.7, 5.1)
#    - `species: list[str]` - species names (ie. 'virginica', 'setosa', ...)
# 3. Mind, that first row in `DATA` is a header and you need to skip it
# 4. Run doctests - all must succeed

# %% Polish
# 1. Rozdziel wartości numeryczne od nazw gatunków
# 2. Wynik przypisz do zmiennych:
#    - `values: list[tuple]` - lista wartości numerycznych (np. 5.8, 2.7, 5.1)
#    - `species: list[str]` - nazwy gatunków (np. 'virginica', 'setosa', ...)
# 3. Zwróć uwagę, że pierwszy wiersz w `DATA` to nagłówek i trzeba go pominąć
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# >>> values
# [(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)]
#
# >>> species
# ['virginica', 'setosa', 'versicolor', 'virginica', 'versicolor', 'setosa']

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from pprint import pprint

>>> assert type(values) is list
>>> assert type(species) is list
>>> assert all(type(x) is tuple for x in values)
>>> assert all(type(x) is str for x in species)

>>> pprint(values)
[(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)]

>>> pprint(species)
['virginica', 'setosa', 'versicolor', 'virginica', 'versicolor', 'setosa']
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
values: list[tuple[float, float, float, float]]
species: list[str]

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

header = DATA[0]
rows = DATA[1:]

# %% Result
values = ...
species = ...

# %% About
# - Name: For Recap ToListTuple
# - Difficulty: medium
# - Lines: 8
# - Minutes: 8

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Load `DATA` from JSON format
# 2. Convert data to `result: list[tuple]`
# 3. Add header as a first line
# 4. Run doctests - all must succeed

# %% Polish
# 1. Wczytaj `DATA` z formatu JSON
# 2. Przekonwertuj dane do `result: list[tuple]`
# 3. Dodaj nagłówek jako pierwszą linię
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# [('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'),
#  ...,
#  (6.4, 3.2, 4.5, 1.5, 'versicolor'),
#  (4.7, 3.2, 1.3, 0.2, 'setosa')]

# %% Why
# - Convert data from `list[dict]` to `list[tuple]`
# - `list[dict]` is used to represent JSON data
# - `list[tuple]` is used to represent CSV data
# - `list[tuple]` is used to represent database rows
# - JSON is the most popular format in web development

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 12), \
'Python 3.12+ required'

>>> from pprint import pprint

>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> result = list(result)
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert len(result) > 0, \
'Variable `result` should not be empty'
>>> assert all(type(row) is tuple for row in result), \
'Variable `result` should be a list[tuple]'

>>> pprint(result)
[('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')]
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
type header = tuple[str, ...]
type row = tuple[float, float, float, float, str]
result: list[header|row]

# %% Data
DATA = [
    {'sepal_length': 5.8, 'sepal_width': 2.7, 'petal_length': 5.1, 'petal_width': 1.9, 'species': 'virginica'},
    {'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'},
    {'sepal_length': 6.4, 'sepal_width': 3.2, 'petal_length': 4.5, 'petal_width': 1.5, 'species': 'versicolor'},
    {'sepal_length': 4.7, 'sepal_width': 3.2, 'petal_length': 1.3, 'petal_width': 0.2, 'species': 'setosa'},
]

# %% Result
result = ...

# %% About
# - Name: For Recap ToListDict
# - Difficulty: medium
# - Lines: 11
# - Minutes: 8

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Convert `list[tuple]` to `list[dict]`
# 2. Define `result: list[dict]`:
#    - key - name from the header
#    - value - measurement or species
# 3. Do not use `zip()` builtin function
# 4. Run doctests - all must succeed

# %% Polish
# 1. Przekonwertuj `list[tuple]` do `list[dict]`
# 2. Zdefiniuj `result: list[dict]`:
#    - klucz - nazwa z nagłówka
#    - wartość - wyniki pomiarów lub gatunek
# 3. Nie używaj wbudowanej funkcji `zip()`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# [{'sepal_length': 5.8, 'sepal_width': 2.7, 'petal_length': 5.1, 'petal_width': 1.9, 'species': 'virginica'},
#  {'sepal_length': 5.1, 'sepal_width': 3.5, 'petal_length': 1.4, 'petal_width': 0.2, 'species': 'setosa'},
#  ...,
#  {'sepal_length': 6.4, 'sepal_width': 3.2, 'petal_length': 4.5, 'petal_width': 1.5, 'species': 'versicolor'},
#  {'sepal_length': 4.7, 'sepal_width': 3.2, 'petal_length': 1.3, 'petal_width': 0.2, 'species': 'setosa'}]

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'

>>> assert all(type(x) is dict for x in result)

>>> from pprint import pprint
>>> pprint(result, width=120, sort_dicts=False)
[{'sepal_length': 5.8, 'sepal_width': 2.7, 'petal_length': 5.1, 'petal_width': 1.9, 'species': 'virginica'},
 {'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'},
 {'sepal_length': 6.4, 'sepal_width': 3.2, 'petal_length': 4.5, 'petal_width': 1.5, 'species': 'versicolor'},
 {'sepal_length': 4.7, 'sepal_width': 3.2, 'petal_length': 1.3, 'petal_width': 0.2, 'species': 'setosa'}]
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: list[dict[str,float|str]]

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

# %% Result
result = ...

# %% About
# - Name: For Recap To Dict
# - Difficulty: medium
# - Lines: 4
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define `result: dict[str, int]` with converted `DATA`
# 2. Check `Example` section to see output format
# 3. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj `result: dict[str, int]` z przekonwertowanym `DATA`
# 2. Sprawdź sekcję `Example` aby zobaczyć format wynikowy
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
#     {'Doctorate': 6,
#      'Prof-school': 6,
#      'Masters': 5,
#      ...
#      'Primary School': 2,
#      'Kindergarten': 1}

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from pprint import pprint

>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is dict, \
'Variable `result` has invalid type, should be dict'

>>> pprint(result, sort_dicts=False)
{'Doctorate': 6,
 'Prof-school': 6,
 'Masters': 5,
 'Bachelor': 5,
 'Engineer': 5,
 'HS-grad': 4,
 'Junior High': 3,
 'Primary School': 2,
 'Kindergarten': 1}
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: dict[str,int]

# %% Data
DATA = {
    6: ['Doctorate', 'Prof-school'],
    5: ['Masters', 'Bachelor', 'Engineer'],
    4: ['HS-grad'],
    3: ['Junior High'],
    2: ['Primary School'],
    1: ['Kindergarten'],
}

# %% Result
result = ...

# %% About
# - Name: For Recap Sentences
# - Difficulty: medium
# - Lines: 15
# - Minutes: 13

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% 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:
#    - sentences (strings separated by periods `.`)
#    - words (strings separated by spaces)
#    - letters (strings without spaces)
#    - characters (including spaces inside sentences, but not comas `,`)
#    - commas (`,`)
#    - adverbs (words ending with "ly")
# 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:
#    - zdań (ciągi znaków rozdzielone kropkami `.`)
#    - słów (ciągi znaków rozdzielone spacjami)
#    - liter (ciągi znaków bez spacji)
#    - znaków (łącznie ze spacjami wewnątrz zdań, ale bez przecinków `,`)
#    - przecinków (`,`)
#    - przysłówków (słów zakończonych na "ly")
# 6. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# {'adverbs': 0,
#  'characters': 347,
#  'commas': 1,
#  'letters': 283,
#  'sentences': 7,
#  'words': 71}

# %% Hints
# - `str.split()`
# - `str.strip()`
# - `str.replace()`
# - `str.count()`
# - `str.endswith()`
# - `list()`
# - `len()`

# %% References
# [1] Kennedy, J.F. Moon Speech - Rice Stadium.
#     Year: 1962.
#     Retrieved: 2021-03-06.
#     URL: http://er.jsc.nasa.gov/seh/ricetalk.htm

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from pprint import pprint

>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is dict, \
'Variable `result` has invalid type, should be dict'

>>> pprint(result)
{'adverbs': 0,
 'characters': 347,
 'commas': 1,
 'letters': 283,
 'sentences': 7,
 'words': 71}
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
result: dict[str,int]

# %% Data
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
"""

# %% Result
result = {
    'adverbs': 0,
    'characters': 0,
    'commas': 0,
    'letters': 0,
    'sentences': 0,
    'words': 0,
}

# %% About
# - Name: For Recap Label Encoder
# - Difficulty: hard
# - Lines: 14
# - Minutes: 13

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Use `DATA: list[tuple]`
# 2. Define `features: list` - list of values (data from columns 0-4)
# 3. Define `labels: list` - species names encoded as integers (column 4)
# 4. To encode and decode species generate from `DATA` two dictionaries:
#    - `decoder: dict` - eg. {0: 'virginica', 1: 'setosa', 2: 'versicolor'}
#    - `encoder: dict` - eg. {'virginica': 0, 'setosa': 1, 'versicolor': 2}
# 5. Run doctests - all must succeed

# %% Polish
# 1. Użyj `DATA: list[tuple]`
# 2. Zdefiniuj `features: list` - lista wartości (dane z kolumn 0-4)
# 3. Zdefiniuj `labels: list` - nazwy gatunków zakodowane jako liczby (kolumna 4)
# 4. Aby móc zakodować i odkodować gatunki wygeneruj z `DATA` dwa słowniki:
#    - `decoder: dict` - np. {0: 'virginica', 1: 'setosa', 2: 'versicolor'}
#    - `encoder: dict` - np. {'virginica': 0, 'setosa': 1, 'versicolor': 2}
# 5. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# 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, 0, 2, 1]
# encoder = {'virginica': 0, 'setosa': 1, 'versicolor': 2}
# decoder = {0: 'virginica', 1: 'setosa', 2: 'versicolor'}

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from pprint import pprint

>>> assert type(features) is list
>>> assert type(labels) is list
>>> assert all(type(x) is tuple for x in features)
>>> assert all(type(x) is int for x in labels)

>>> pprint(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)]

>>> pprint(labels)
[0, 1, 2, 0, 2, 1]

>>> encoder
{'virginica': 0, 'setosa': 1, 'versicolor': 2}

>>> decoder
{0: 'virginica', 1: 'setosa', 2: 'versicolor'}
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
features: list[tuple[float,float,float,float,str]]
labels: list[int]
encoder: dict[str,int]
decoder: dict[int,str]

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

header = DATA[0]
rows = DATA[1:]

# %% Result
features = ...
labels = ...
encoder = ...
decoder = ...