6.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]

6.10.1. Assignments

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


Code 6.39. Solution
"""
* 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': '255.255.255.255', 'hosts': ['broadcasthost']},
     {'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
255.255.255.255 broadcasthost
::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 = ...

Code 6.40. Solution
"""
* 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': '255.255.255.255', 'hosts': ['broadcasthost']},
     {'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
255.255.255.255 broadcasthost
::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: map
result = ...