12.2. Comprehension Types

12.2.1. List Comprehension

  • [x for x in ...]

  • list(x for x in ...)

Short syntax:

>>> [x for x in range(0,5)]
[0, 1, 2, 3, 4]

Long Syntax:

>>> list(x for x in range(0,5))
[0, 1, 2, 3, 4]

12.2.2. Set Comprehension

  • {x for x in ...}

  • set(x for x in ...)

  • Unique elements

  • Ordered by hash of elements

Short Syntax:

>>> {x for x in range(0, 5)}
{0, 1, 2, 3, 4}

Long Syntax:

>>> set(x for x in range(0, 5))
{0, 1, 2, 3, 4}

Set contains only unique elements, and are ordered by hash:

>>> DATA = ['a', 'b', 'c', 'a']
>>>
>>> {x for x in DATA}  
{'b', 'a', 'c'}

12.2.3. Dict Comprehension

  • {x:x for x in ...}

  • dict((x,x) for x in ...)

Short syntax:

>>> {x:None for x in range(0,5)}
{0: None, 1: None, 2: None, 3: None, 4: None}

Long syntax:

>>> dict((x,None) for x in range(0,5))
{0: None, 1: None, 2: None, 3: None, 4: None}

Example:

>>> {x:x+10 for x in range(0,5)}
{0: 10, 1: 11, 2: 12, 3: 13, 4: 14}

Remember that in dict duplicating items are overridden by the latter:

>>> data = {
...     'commander': 'Mark Watney',
...     'commander': 'Melissa Lewis',
... }
>>>
>>> data
{'commander': 'Melissa Lewis'}

While generating dict with unique keys, there are no collisions:

>>> {x:None for x in range(0,5)}
{0: None, 1: None, 2: None, 3: None, 4: None}

Although when generating dict with constant key, it will be overridden by the last one:

>>> {None:x for x in range(0,5)}
{None: 4}

12.2.4. Tuple Comprehension

  • There is no short syntax for Tuple Comprehension

  • Round brackets will create Generator Expression

Short syntax:

>>> (x for x in range(0,5))  
<generator object <genexpr> at 0x...>

Long syntax:

>>> tuple(x for x in range(0,5))
(0, 1, 2, 3, 4)

Example:

>>> data = (x for x in range(0,5))
>>>
>>> for result in data:
...     print(result)
...
0
1
2
3
4

12.2.5. Case Study

>>> data = [x for x in range(0,5)]          # list comprehension
>>> data = (x for x in range(0,5))          # generator expression
>>> data = {x for x in range(0,5)}          # set comprehension
>>> data = {x:x for x in range(0,5)}        # dict comprehension
>>> data = list(x for x in range(0,5))
>>> data = tuple(x for x in range(0,5))
>>> data = set(x for x in range(0,5))
>>> data = dict((x,x) for x in range(0,5))
>>> data = all(x for x in range(0,5))
>>> data = any(x for x in range(0,5))
>>> data = bool(x for x in range(0,5))
>>> data = sum(x for x in range(0,5))
>>> data = min(x for x in range(0,5))
>>> data = max(x for x in range(0,5))
>>> data = hash(x for x in range(0,5))
>>> data = callable(x for x in range(0,5))
>>> data = len(x for x in range(0,5))
Traceback (most recent call last):
TypeError: object of type 'generator' has no len()

12.2.6. Use Case - 1

  • Sum

>>> sum(x for x in range(0,5))
10

12.2.7. Use Case - 2

  • Reverse dict - swap keys with values

>>> DATA = {
...     'mlewis': 'Melissa Lewis',
...     'mwatney': 'Mark Watney',
...     'rmartinez': 'Rick Martinez',
... }
>>>
>>> result = {v:k for k,v in DATA.items()}
>>>
>>> result  
{'Melissa Lewis': 'mlewis',
 'Mark Watney': 'mwatney',
 'Rick Martinez': 'rmartinez'}

12.2.8. Use Case - 3

  • Reverse dict - swap keys with values

  • Dict Reversal Collision

Value collision while reversing dict (note that both b and c has value 2)

>>> DATA = {'a': 1, 'b': 2, 'c': 2}
>>>
>>> {v:k for k,v in DATA.items()}
{1: 'a', 2: 'c'}

12.2.9. Use Case - 4

  • Even or Odd

>>> DATA = [1, 2, 3, 4]
>>> result = {}
>>>
>>> for x in DATA:
...     is_even = (x % 2 == 0)
...     result.update({x: is_even})
>>>
>>> print(result)
{1: False, 2: True, 3: False, 4: True}
>>> DATA = [1, 2, 3, 4]
>>>
>>> {x:(x%2==0) for x in DATA}
{1: False, 2: True, 3: False, 4: True}

12.2.10. 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 Types Dict
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% English
# 1. Define `result: dict` with:
#    - `key: int` integer from 0 to 5 (exclusive)
#    - `value: int` value for key squared (raised to the power of 2)
#    - example: `{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}`
# 2. Non-functional requirements:
#    - Use list comprehension
#    - Use `range()` function
#    - Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj `result: dict` z:
#    - `klucz: int` liczba całkowita od 0 do 5 (rozłącznie)
#    - `wartość: int` wartość dla klucza podniesiona do kwadratu
#    - przykład: `{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}`
# 2. Non-functional requirements:
#    - Użyj list comprehension
#    - Użyj funkcji `range()`
#    - Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - `[... for ... in ...]`
# - `range(start,stop)`
# - `start is inclusive`
# - `stop is exclusive`

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

>>> assert type(result) is dict, \
'Result should be a dict'
>>> assert all(type(x) is int for x in result), \
'Result should be a list of int'

>>> result
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
"""

# `key: int` integer from 0 to 5 (exclusive)
# `value: int` value for key squared (raised to the power of 2)
# example: `{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}`
# type: dict[int,int]
result = ...


# %% 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 Types Swap
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% English
# 1. Reverse dict (swap keys and values)
# 2. Run doctests - all must succeed

# %% Polish
# 1. Odwróć dict (zamień klucze z wartościami)
# 2. Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - `dict.items()`

# %% Tests
"""
>>> 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 dict, \
'Variable `result` has invalid type, should be dict'

>>> assert all(type(x) is str for x in result.keys())
>>> assert all(type(x) is int for x in result.values())
>>> assert len(result.keys()) == 3

>>> assert 'virginica' in result.keys()
>>> assert 'setosa' in result.keys()
>>> assert 'versicolor' in result.keys()

>>> assert 0 in result.values()
>>> assert 1 in result.values()
>>> assert 2 in result.values()

>>> from pprint import pprint
>>> pprint(result, width=20, sort_dicts=False)
{'virginica': 0,
 'setosa': 1,
 'versicolor': 2}
"""

DATA = {
    0: 'virginica',
    1: 'setosa',
    2: 'versicolor',
}

# Reverse dict (swap keys and values)
# type: dict[str,int]
result = ...


# %% 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 Types Months
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% English
# 1. Convert `DATA` into `result: dict`:
#    - Keys: month number
#    - Values: month name
# 2. Use dict comprehension
# 3. Run doctests - all must succeed

# %% Polish
# 1. Przekonwertuj `DATA` w `result: dict`:
#    - klucz: numer miesiąca
#    - wartość: nazwa miesiąca
# 2. Użyj dict comprehension
# 3. Uruchom doctesty - wszystkie muszą się powieść

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

>>> from pprint import pprint

>>> type(result)
<class 'dict'>
>>> 0 not in result
True
>>> 13 not in result
True
>>> result[1] == 'January'
True

>>> assert all(type(x) is int for x in result.keys())
>>> assert all(type(x) is str for x in result.values())

>>> pprint(result)
{1: 'January',
 2: 'February',
 3: 'March',
 4: 'April',
 5: 'May',
 6: 'June',
 7: 'July',
 8: 'August',
 9: 'September',
 10: 'October',
 11: 'November',
 12: 'December'}
"""

DATA = [
    (1, 'January'),
    (2, 'February'),
    (3, 'March'),
    (4, 'April'),
    (5, 'May'),
    (6, 'June'),
    (7, 'July'),
    (8, 'August'),
    (9, 'September'),
    (10, 'October'),
    (11, 'November'),
    (12, 'December'),
]

# Convert `DATA` into `result: dict`:
# - Keys: month number
# - Values: month name
# Use dict comprehension
# type: dict[int,str]
result = ...


# %% 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 Types Zfill
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% English
# 1. Define `result: dict` with `DATA` converted into:
#    - Keys: month number
#    - Values: month name
# 2. Month number must be two letter string (zero padded)
# 3. Use dict comprehension
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj `result: dict` z `DATA` przekonwertowanym w:
#    - klucz: numer miesiąca
#    - wartość: nazwa miesiąca
# 2. Numer miesiąca ma być dwuznakowym stringiem (wypełnij zerem)
# 3. Użyj rozwinięcia słownikowego
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - `f'{number:02}'`
# - `str.zfill()`

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

>>> from pprint import pprint

>>> type(result)
<class 'dict'>
>>> '00' not in result
True
>>> '13' not in result
True
>>> result['01'] == 'January'
True

>>> assert all(type(x) is str for x in result.keys())
>>> assert all(type(x) is str for x in result.values())
>>> assert all(len(x) == 2 for x in result.keys())

>>> pprint(result)
{'01': 'January',
 '02': 'February',
 '03': 'March',
 '04': 'April',
 '05': 'May',
 '06': 'June',
 '07': 'July',
 '08': 'August',
 '09': 'September',
 '10': 'October',
 '11': 'November',
 '12': 'December'}
"""

DATA = [
    (1, 'January'),
    (2, 'February'),
    (3, 'March'),
    (4, 'April'),
    (5, 'May'),
    (6, 'June'),
    (7, 'July'),
    (8, 'August'),
    (9, 'September'),
    (10, 'October'),
    (11, 'November'),
    (12, 'December'),
]

# Define `result: dict` with `DATA` converted into:
# - Keys: month number
# - Values: month name
# Month number must be two letter string (zero padded)
# Hints `f'{number:02}'` or `str.zfill()`
# Use dict comprehension
# type: dict[str,str]
result = ...