12.6. Comprehension Nested

12.6.1. Syntax

result = [<RETURN> for <VARIABLE> in <ITERABLE> for <VARIABLE> in <ITERABLE>]
result = [<RETURN>
          for <VARIABLE> in <ITERABLE>
          for <VARIABLE> in <ITERABLE>]

12.6.2. Problem

>>> DATA = {
...     6: ['Doctorate', 'Prof-school'],
...     5: ['Masters', 'Bachelor', 'Engineer'],
...     4: ['HS-grad'],
...     3: ['Junior High'],
...     2: ['Primary School'],
...     1: ['Kindergarten'],
... }
>>>
>>>
>>> result = {}
>>> for lvl, titles in DATA.items():
...     for title in titles:
...         result[title] = lvl
>>>
>>> print(result)  
{'Doctorate': 6,
 'Prof-school': 6,
 'Masters': 5,
 'Bachelor': 5,
 'Engineer': 5,
 'HS-grad': 4,
 'Junior High': 3,
 'Primary School': 2,
 'Kindergarten': 1}

12.6.3. Solution

>>> DATA = {
...     6: ['Doctorate', 'Prof-school'],
...     5: ['Masters', 'Bachelor', 'Engineer'],
...     4: ['HS-grad'],
...     3: ['Junior High'],
...     2: ['Primary School'],
...     1: ['Kindergarten'],
... }
>>>
>>>
>>> result = {title: lvl
...           for lvl, titles in DATA.items()
...           for title in titles}
>>>
>>> print(result)  
{'Doctorate': 6,
 'Prof-school': 6,
 'Masters': 5,
 'Bachelor': 5,
 'Engineer': 5,
 'HS-grad': 4,
 'Junior High': 3,
 'Primary School': 2,
 'Kindergarten': 1}

12.6.4. Performance

>>> DATA = {
...     6: ['Doctorate', 'Prof-school'],
...     5: ['Masters', 'Bachelor', 'Engineer'],
...     4: ['HS-grad'],
...     3: ['Junior High'],
...     2: ['Primary School'],
...     1: ['Kindergarten'],
... }
>>> # %%timeit -r 1000 -n 1000
>>> result = {title: lvl
...           for lvl, titles in DATA.items()
...           for title in titles}
>>> # 2.22 µs ± 138 ns per loop (mean ± std. dev. of 1000 runs, 1000 loops each)
>>> # %%timeit -r 1000 -n 1000
>>> result = {t:l for l,ts in DATA.items() for t in ts}
>>> # 2.22 µs ± 181 ns per loop (mean ± std. dev. of 1000 runs, 1000 loops each)
>>> # %%timeit -r 1000 -n 1000
>>> result = {}
>>> for lvl, titles in DATA.items():
...     for title in titles:
...         result[title] = lvl
>>> # 2.24 µs ± 152 ns per loop (mean ± std. dev. of 1000 runs, 1000 loops each)

12.6.5. Convert to CSV

>>> 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 = '\n'.join(','.join(str(x) for x in row) for row in DATA)
>>>
>>> print(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
>>> result = [','.join(str(x) for x in row) for row in DATA]
>>> result = '\n'.join(result)
>>>
>>> print(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
>>> data = []
>>> for row in DATA:
...     line = ','.join(str(x) for x in row)
...     data.append(line)
>>>
>>> result = '\n'.join(data)
>>>
>>> print(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

12.6.6. Parse CSV

>>> DATA = '5.8,2.7,5.1,1.9\n5.1,3.5,1.4,0.2\n5.7,2.8,4.1,1.3'
>>>
>>> result = []
>>>
>>> for row in DATA.splitlines():
...     row = row.split(',')
...     result.append(row)
>>>
>>> print(result)  
[['5.8', '2.7', '5.1', '1.9'],
 ['5.1', '3.5', '1.4', '0.2'],
 ['5.7', '2.8', '4.1', '1.3']]
>>> DATA = '5.8,2.7,5.1,1.9\n5.1,3.5,1.4,0.2\n5.7,2.8,4.1,1.3'
>>>
>>> [row.split(',') for row in DATA.splitlines()]  
[['5.8', '2.7', '5.1', '1.9'],
 ['5.1', '3.5', '1.4', '0.2'],
 ['5.7', '2.8', '4.1', '1.3']]
>>> DATA = '5.8,2.7,5.1,1.9\n5.1,3.5,1.4,0.2\n5.7,2.8,4.1,1.3'
>>>
>>> [[float(x) for x in row.split(',')] for row in DATA.splitlines()]  
[[5.8, 2.7, 5.1, 1.9],
 [5.1, 3.5, 1.4, 0.2],
 [5.7, 2.8, 4.1, 1.3]]
>>> DATA = '5.8,2.7,5.1,1.9,virginica\n5.1,3.5,1.4,0.2,setosa\n5.7,2.8,4.1,1.3,versicolor'
>>>
>>> def convert(x):
...     try:
...         return float(x)
...     except ValueError:
...         return x
>>>
>>> [[convert(x) for x in row.split(',')] for row in DATA.splitlines()]  
[[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']]

12.6.7. Assignments

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

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

# %% About
# - Name: Comprehension Nested Dict
# - Difficulty: easy
# - Lines: 1
# - Minutes: 5

# %% English
# 1. Convert to `result: dict[str,int]`
# 2. Use nested dict comprehension
# 3. Run doctests - all must succeed

# %% Polish
# 1. Przekonwertuj do `result: dict[str,int]`
# 2. Użyj zagnieżdżonego rozwinięcia słownikowego
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - nested `for`
# - `dict.items()`
# - `str()`

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

>>> from pprint import pprint

>>> type(result)
<class '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}
"""

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

# Converted DATA
# type: dict[str,int]
result = ...