6.4. Idiom Enumerate

  • Enumerate sequences

  • Built-in generator like (lazy evaluated)

  • enumerate(*iterables)

  • required *iterables - 1 or many sequences or iterator object

  • Return an enumerate object

  • The enumerate object yields pairs containing a count (from start, which defaults to zero) and a value yielded by the iterable argument.

>>> from inspect import isgeneratorfunction, isgenerator
>>>
>>>
>>> isgeneratorfunction(enumerate)
False
>>> result = enumerate(['a', 'b', 'c'])
>>> isgenerator(result)
False

6.4.1. Problem

>>> months = ['January', 'February', 'March']
>>> result = []
>>>
>>> i = 0
>>>
>>> for month in months:
...     result.append((i, month))
...     i += 1
>>>
>>> result
[(0, 'January'), (1, 'February'), (2, 'March')]

6.4.2. Solution

>>> months = ['January', 'February', 'March']
>>> result = enumerate(months)
>>>
>>> list(result)
[(0, 'January'), (1, 'February'), (2, 'March')]

6.4.3. Lazy Evaluation

>>> months = ['January', 'February', 'March']
>>> result = enumerate(months)
>>>
>>> next(result)
(0, 'January')
>>> next(result)
(1, 'February')
>>> next(result)
(2, 'March')
>>> next(result)
Traceback (most recent call last):
StopIteration

6.4.4. Dict Conversion

>>> months = ['January', 'February', 'March']
>>> result = enumerate(months)
>>>
>>> dict(result)
{0: 'January', 1: 'February', 2: 'March'}
>>> months = ['January', 'February', 'March']
>>> result = enumerate(months, start=1)
>>>
>>> dict(result)
{1: 'January', 2: 'February', 3: 'March'}
>>> months = ['January', 'February', 'March']
>>> result = {f'{i:02}':month for i,month in enumerate(months, start=1)}
>>>
>>> print(result)
{'01': 'January', '02': 'February', '03': 'March'}

6.4.5. Using in a Loop

>>> months = ['January', 'February', 'March']
>>>
>>> for i, month in enumerate(months, start=1):
...     print(f'{i} -> {month}')
1 -> January
2 -> February
3 -> March

6.4.6. Assignments

Code 6.15. Solution
"""
* Assignment: Idiom Enumerate Start
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 3 min

English:
    1. Convert `MONTH` into dict:
        a. key: int - month number
        b. value: str - month name
    2. Use enumerate()
    3. Run doctests - all must succeed

Polish:
    1. Przekonwertuj `MONTH` w słownik:
        a. klucz: int - numer miesiąca
        b. wartość: str - nazwa miesiąca
    2. Użyj enumerate()
    3. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `dict()`
    * `enumerate()`

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from pprint import pprint

    >>> assert type(result)
    >>> assert -1 not in result
    >>> assert 0 in result
    >>> assert 12 not in result
    >>> assert 13 not in result
    >>> assert result[0] == 'January'

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

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

MONTHS = ['January', 'February', 'March', 'April',
          'May', 'June', 'July', 'August', 'September',
          'October', 'November', 'December']

# number and month name
# type: dict[int,str]
result = ...

Code 6.16. Solution
"""
* Assignment: Idiom Enumerate Start
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 3 min

English:
    1. Convert `MONTH` into dict:
        a. key: int - month number
        b. value: str - month name
    2. Use enumerate() starting with 1
    3. Run doctests - all must succeed

Polish:
    1. Przekonwertuj `MONTH` w słownik:
        a. klucz: int - numer miesiąca
        b. wartość: str - nazwa miesiąca
    2. Użyj enumerate() zaczynając od 1
    3. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `dict()`
    * `enumerate()`

Tests:
    >>> import sys; sys.tracebacklimit = 0

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

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

MONTHS = ['January', 'February', 'March', 'April',
          'May', 'June', 'July', 'August', 'September',
          'October', 'November', 'December']

# number and month name
# type: dict[int,str]
result = ...

Code 6.17. Solution
"""
* Assignment: Idiom Enumerate Start
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 3 min

English:
    1. Convert `MONTH` into dict:
        a. key: str - month number (convert to str)
        b. value: str - month name
    2. Use enumerate() starting with 1
    3. Run doctests - all must succeed

Polish:
    1. Przekonwertuj `MONTH` w słownik:
        a. klucz: str - numer miesiąca (zamień na str)
        b. wartość: str - nazwa miesiąca
    2. Użyj enumerate() zaczynając od 1
    3. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * dict comprehension
    * `str()`
    * `enumerate()`

Tests:
    >>> import sys; sys.tracebacklimit = 0

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

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

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

MONTHS = ['January', 'February', 'March', 'April',
          'May', 'June', 'July', 'August', 'September',
          'October', 'November', 'December']

# number and month name
# type: dict[str,str]
result = ...

Code 6.18. Solution
"""
* Assignment: Idiom Enumerate ZeroPadded
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 3 min

English:
    1. Convert `MONTH` into dict:
        a. key: str - month number
        b. value: str - month name
    2. Use enumerate() starting with 1
    3. Month number must be two letter string
       (zero padded) - np. 01, 02, ..., 09, 10, 11, 12
    4. Run doctests - all must succeed

Polish:
    1. Przekonwertuj `MONTH` w słownik:
        a. klucz: str - numer miesiąca
        b. wartość: str - nazwa miesiąca
    2. Użyj enumerate() zaczynając od 1
    3. Numer miesiąca ma być dwuznakowym stringiem
       (dopełnionym zerem) - np. 01, 02, ..., 09, 10, 11, 12
    4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * dict comprehension
    * `enumerate()`
    * `str.zfill()`
    * `f'{number:02}'`

Tests:
    >>> import sys; sys.tracebacklimit = 0

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

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

MONTHS = ['January', 'February', 'March', 'April',
          'May', 'June', 'July', 'August', 'September',
          'October', 'November', 'December']

# With zero-padded number and month name
# type: dict[str,str]
result = ...

Code 6.19. Solution
"""
* Assignment: Idiom Enumerate Dict
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 min

English:
    1. Define `result: dict`
    2. Assign to `result` converted `DATA` to `dict`
    3. Use `enumerate()`
    4. Run doctests - all must succeed

Polish:
    1. Zdefiniu `result: dict`
    2. Przypisz do `result` przekonwertowane `DATA` do `dict`
    3. Użyj `enumerate()`
    4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `dict()`
    * `enumerate()`

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> assert type(result) is dict, \
    'Variable `result` has invalid type, should be dict'

    >>> assert all(type(x) is int for x in result.keys()), \
    'All dict keys should be int'

    >>> assert all(type(x) is str for x in result.values()), \
    'All dict values should be str'

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

DATA = ['setosa', 'versicolor', 'virginica']

# Dict with enumerated DATA
# type: dict[int,str]
result = ...

Code 6.20. Solution
"""
* Assignment: Idiom Enumerate Impl
* Complexity: medium
* Lines of code: 7 lines
* Time: 13 min

English:
    1. Write own implementation of a built-in `enumerate()` function
    2. Define function `myenumerate` with parameters:
        a. parameter `iterable: list | tuple`
        b. parameter `start: int`
    3. Don't validate arguments and assume, that user will:
        a. always pass valid type of arguments
        b. iterable length will always be greater than 0
    4. Do not use built-in function `enumerate()`
    5. Run doctests - all must succeed

Polish:
    1. Zaimplementuj własne rozwiązanie wbudowanej funkcji `enumerate()`
    2. Zdefiniuj funkcję `myenumerate` z parametrami:
        a. parametr `iterable: list | tuple`
        b. parametr `start: int`
    3. Nie waliduj argumentów i przyjmij, że użytkownik:
        a. zawsze poda argumenty poprawnych typów
        b. długość iterable będzie większa od 0
    4. Nie używaj wbudowanej funkcji `enumerate()`
    5. Uruchom doctesty - wszystkie muszą się powieść

Hint:
    * https://github.com/python/cpython/blob/main/Objects/enumobject.c
    * `range()`
    * `len()`
    * `list.appned()`

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from inspect import isfunction
    >>> assert isfunction(myenumerate)

    >>> myenumerate(['January', 'February', 'March'])
    [(0, 'January'), (1, 'February'), (2, 'March')]

    >>> myenumerate(['January', 'February', 'March'], start=1)
    [(1, 'January'), (2, 'February'), (3, 'March')]

    >>> dict(myenumerate(['January', 'February', 'March'], start=1))
    {1: 'January', 2: 'February', 3: 'March'}
"""

# Write own implementation of a built-in `enumerate()` function
# Define function `myenumerate` with parameters: `iterable`, `start`
# type: Callable[[Iterable, int], list[tuple]]
def myenumerate(iterable, start=0):
    ...