# 13.4. Iterator 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


## 13.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')]


## 13.4.2. Solution

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


## 13.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


## 13.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'}


## 13.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


## 13.4.6. Assignments

"""
* Assignment: Iterator Enumerate Start
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 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 = ...


"""
* Assignment: Iterator Enumerate Start
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 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 = ...


"""
* Assignment: Iterator Enumerate Start
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 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 = ...


"""
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 2 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 = ...


"""
* Assignment: Iterator 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. Zdefiniuj 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 = ...


"""
* Assignment: Iterator 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.append()

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):
...