4.13. Idiom Chain¶
itertools.chain()
Generator like (lazy evaluated)
>>> 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.13.1. Assignments¶
"""
* Assignment: Idiom Reduce Chain
* Required: yes
* 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 Filter Apply
* Required: yes
* Complexity: easy
* Lines of code: 11 lines
* Time: 8 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"""
# type: list[dict]
result = ...
"""
* Assignment: Idiom Filter Apply
* Required: yes
* 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}