# 4.10. Idiom Apply¶

>>> def square(x):
...     return x ** 2
>>>
>>> def even(x):
...     return x % 2 == 0
>>>
>>>
>>> result = range(0,10)
>>> result = map(square, result)
>>> result = filter(even, result)
>>>
>>> for value in result:
...     print(value)
...     if value > 3:
...         break
0
4
>>>
>>> next(result)
16
>>>
>>> list(result)
[36, 64]


## 4.10.1. Assignments¶

"""
* Assignment: Idiom MapFilter Chain
* Type: class assignment
* Complexity: easy
* Lines of code: 4 lines
* Time: 3 min

English:
1. Use range() to get numbers:
a. from 0 (inclusive)
b. to 10 (exclusive)
2. Redefine result with odd numbers from result
3. Redefine result with cubed numbers from result
4. Redefine result with evaluated result
5. At the end result must be a list type
6. Run doctests - all must succeed

Polish:
1. Użyj range() aby otrzymać liczby:
a. od 0 (włącznie)
b. do 10 (rozłącznie)
2. Przedefiniuj result z nieparzystymi liczbami z result
3. Przedefiniuj result z podniesionymi do sześcianiu liczbami z result
4. Przedefiniuj result z ewaluaownym result
5. Na końcu result musi być typu list
6. Uruchom doctesty - wszystkie muszą się powieść

Hints:
* range()
* map()
* filter()
* list()

Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isfunction

>>> assert isfunction(odd), \
'Object odd must be a function'
>>> assert isfunction(cube), \
'Object cube must be a function'
>>> assert result is not Ellipsis, \
'Assign result to variable: result'
>>> assert type(result) is list, \
'Variable result has invalid type, should be list'
>>> assert all(type(x) is int for x in result), \
'All rows in result should be int'

>>> result
[1, 27, 125, 343, 729]
"""

def odd(x):
return x % 2

def cube(x):
return x ** 3

# Range from 0 to 10 (exclusive)
# type: range
result = ...

# Filter odd numbers
# type: filter
result = ...

# Cube result
# type: map
result = ...

# Get list of results
# type: list[int]
result = ...


"""
* Assignment: Idiom MapFilter Apply
* Type: class assignment
* Complexity: easy
* Lines of code: 3 lines
* Time: 5 min

English:
1. Define result: list[dict], where each dict has keys:
* ip: str
* hosts: list[str]
2. Skip comments (#) and empty lines
3. Extract from each line: ip and hosts
4. Add ip and hosts to result as a dict, example:
{'ip': '127.0.0.1', 'hosts': ['localhost', 'astromatt']}
5. Each line must be a separate dict
4. Run doctests - all must succeed

Polish:
1. Zdefiniuj result: list[dict], gdzie każdy dict ma klucze:
* ip: str
* hosts: list[str]
2. Pomiń komentarze (#) i puste linie
3. Wyciągnij z każdej linii: ip i hosts
4. Dodaj ip i hosts do result jako słownik, przykład:
{'ip': '127.0.0.1', 'hosts': ['localhost', 'astromatt']}
5. Każda linia ma być osobnym słownikiem
4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
* filter()
* map()
* len()
* str.split()
* str.startswith()

Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isfunction

>>> assert isfunction(valid), \
'Object valid must be a function'

>>> assert result is not Ellipsis, \
'Assign result to variable: result'

>>> result = list(result)
>>> assert type(result) is list, \
'Evaluated result has invalid type, should be list'

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

>>> assert all(type(key) is str
...            for row in result
...            for key in row.keys()), \
'All rows in result should be dict'

>>> list(result)  # doctest: +NORMALIZE_WHITESPACE
[{'ip': '127.0.0.1', 'hosts': ['localhost', 'astromatt']},
{'ip': '10.13.37.1', 'hosts': ['nasa.gov', 'esa.int']},
{'ip': '::1', 'hosts': ['localhost']}]
"""

DATA = """##
# /etc/hosts structure:
#   - IPv4 or IPv6
#   - Hostnames
##

127.0.0.1       localhost astromatt
10.13.37.1      nasa.gov esa.int
::1             localhost"""

def valid(line: str) -> bool:
if len(line) == 0:
return False
if line.startswith('#'):
return False
return True

def parse(line: str) -> dict:
ip, *hosts = line.split()
return {'ip': ip, 'hosts': hosts}

# type: list[dict]
result = ...


"""
* Assignment: Idiom MapFilter Apply
* Type: class assignment
* Complexity: easy
* Lines of code: 3 lines
* Time: 3 min

English:
0. Note, this assignment differs from previous by one character in DATA
1. Filter-out lines from DATA when:
a. line is empty
b. line has only spaces
c. starts with # (comment)
2. Use filter() to apply function valid() to DATA
3. Define result: filter with result
4. Run doctests - all must succeed

Polish:
0. Zauważ, że to zadanie od poprzedniego różni się jednym znakiem w DATA
1. Odfiltruj linie z DATA gdy:
a. linia jest pusta
b. linia ma tylko spacje
c. zaczyna się od # (komentarz)
2. Użyj filter() aby zaaplikować funkcję valid() do DATA
3. Zdefiniuj result: filter z wynikiem
4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
* filter()

Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isfunction

>>> assert isfunction(parse), \
'Object parse must be a function'

>>> assert result is not Ellipsis, \
'Assign result to variable: result'

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

>>> result = list(result)
>>> assert type(result) is list, \
'Evaluated result has invalid type, should be list'

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

>>> list(result)  # doctest: +NORMALIZE_WHITESPACE
[{'ip': '127.0.0.1', 'hosts': ['localhost']},
{'ip': '127.0.0.1', 'hosts': ['astromatt']},
{'ip': '10.13.37.1', 'hosts': ['nasa.gov', 'esa.int']},
{'ip': '::1', 'hosts': ['localhost']}]

"""

DATA = """##
# /etc/hosts structure:
#   - IPv4 or IPv6
#   - Hostnames
##

127.0.0.1       localhost
127.0.0.1       astromatt
10.13.37.1      nasa.gov esa.int
::1             localhost"""

def valid(line: str) -> bool:
if len(line) == 0:
return False
if line.startswith('#'):
return False
return True

def parse(line: str) -> dict:
ip, *hosts = line.split()
return {'ip': ip, 'hosts': hosts}