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


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


## 4.4.2. Solution¶

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


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


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


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


## 4.4.6. Assignments¶

"""
* 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 = ...


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

English:
1. Convert MONTH into dict:
a. Keys: month number
b. Values: month name
2. Use dict() and enumerate()
3. Run doctests - all must succeed

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

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[str,str]
result = ...


"""
* Type: class assignment
* Complexity: easy
* Lines of code: 1 lines
* Time: 3 min

English:
1. Use dict comprehension and enumerate
2. Convert MONTH into result: dict[str,str]:
a. Keys: month number
b. Values: month name
3. Month number must be two letter string
(zero padded) - f'{number:02}'
4. Run doctests - all must succeed

Polish:
1. Użyj rozwinięcia słownikowego i enumeracji
2. Przekonwertuj MONTH w result: dict[str,str]:
a. klucz: numer miesiąca
b. wartość: nazwa miesiąca
3. Numer miesiąca ma być dwuznakowym stringiem
(wypełnij zerem) - f'{number:02}'
4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
* enumerate()
* 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: Idiom Enumerate LabelEncoder
* Complexity: medium
* Lines of code: 3 lines
* Time: 5 min

English:
1. From DATA separate header (first line) from other lines
2. Split header by comma , into:
a. nrows - number of rows
b. nfeatures - number of features
c. class_labels - species names
3. Generate result: dict[int,str] from class_labels:
a. 0: setosa
b. 1: virginica
c. 2: versicolor
4. Use enumerate()
5. Run doctests - all must succeed

Polish:
1. Z DATA odseparuj nagłówek (pierwsza linia) od pozostałych linii
2. Rozdziel nagłówek po przecinku , na:
a. nrows - liczba wierszy
b. nfeatures - liczba cech
c. class_labels - nazwy gatunków
3. Wygeneruj result: dict[int,str] z class_labels:
a. 0: setosa
b. 1: virginica
c. 2: versicolor
4. Użyj enumerate()
5. Uruchom doctesty - wszystkie muszą się powieść

Hints:
* dict(enumerate())
* str.splitlines()
* str.split()
* str.strip()
* line: "3,4,setosa,virginica,versicolor" is not an error
* 3 - rows
* 4 - number of features (values)
* setosa,virginica,versicolor - if 0 then setosa, if 1 then virginica, etc.

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

>>> assert result is not Ellipsis, \
'Assign result to variable: result'
>>> 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 keys in result should be int'
>>> assert all(type(x) is str for x in result.values()), \
'All values in result should be str'

>>> result  # doctest: +NORMALIZE_WHITESPACE
{0: 'setosa', 1: 'virginica', 2: 'versicolor'}
"""

DATA = """3,4,setosa,virginica,versicolor
5.8,2.7,5.1,1.9,1
5.1,3.5,1.4,0.2,0
5.7,2.8,4.1,1.3,2"""

# values from file (note the list[tuple] format!)
# type: dict[int,str]
result = ...


"""
* 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

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