4.10. Idiom Reduce

  • Reduce sequence using function

  • Built-in

>>> 1 + 2
3
>>> 1 + 2 + 3 + 4
10

4.10.1. Syntax

4.10.2. Problem

>>> def add(x, y):
...     return x + y
>>>
>>>
>>> DATA = [1, 2, 3, 4]
>>> result = 0
>>>
>>> for element in DATA:
...     result = add(result, element)
>>>
>>> print(result)
10

4.10.3. Solution

>>> from functools import reduce
>>>
>>>
>>> def add(x, y):
...     return x + y
>>>
>>>
>>> DATA = [1, 2, 3, 4]
>>>
>>> reduce(add, DATA)
10

4.10.4. Rationale

>>> from functools import reduce
>>> from operator import mul
>>>
>>>
>>> DATA = [1, 2, 3, 4]
>>>
>>> reduce(mul, DATA)
24
>>> from functools import reduce
>>>
>>>
>>> DATA = [1, 2, 3, 4]
>>>
>>> reduce(min, DATA)
1
>>> reduce(max, DATA)
4

4.10.5. Map Reduce

../../_images/idiom-reduce-mapreduce.gif

4.10.6. Assignments

Code 4.19. Solution
"""
* 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: Iterator[int]
result = ...

# Filter odd numbers
# type: Iterator[int]
result = ...

# Cube result
# type: Iterator[int]
result = ...

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


Code 4.20. Solution
"""
* Assignment: Idiom Reduce Evaluate
* Required: yes
* Complexity: easy
* Lines of code: 2 lines
* Time: 3 min

English:
    1. Define `result: float` with arithmetic mean of `DATA`
    2. Note, that all the time you are working on a data stream
    3. Run doctests - all must succeed

Polish:
    1. Zdefiniuj `result: float` ze średnią arytmetyczną z `DATA`
    2. Zwróć uwagę, że cały czas pracujesz na strumieniu danych
    3. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * type cast to `list()` to expand generator before calculating mean
    * `mean = sum(...) / len(...)`
    * TypeError: object of type 'map' has no len()
    * ZeroDivisionError: division by zero

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 float, \
    'Variable `result` has invalid type, should be float'

    >>> result
    245.0
"""

def odd(x):
    return x % 2


def cube(x):
    return x ** 3


DATA = range(0, 10)
DATA = filter(odd, DATA)
DATA = map(cube, DATA)

# Calculate mean of DATA
# type: float
result = ...


Code 4.21. Solution
"""
* Assignment: Idiom Reduce Chain
* Complexity: easy
* Lines of code: 5 lines
* Time: 5 min

English:
    1. Define `result` with numbers from `range()`:
       a. from 0 (inclusive)
       b. to 10 (exclusive)
    2. Use `filter()` to get odd numbers from `result`
       (and assign to `result`)
    3. Use `map()` to cube all numbers in `result`
    4. Create `result: float` with arithmetic mean of `result`
    5. Do not use `lambda` expressions
    6. Note, that all the time you are working on one data stream
    7. Run doctests - all must succeed

Polish:
    1. Zdefiniu `result` z liczbami z `range()`:
       a. od 0 (włącznie)
       b. do 10 (rozłącznie)
    2. Użyj `filter()` aby otrzymać liczby nieparzyste z `result`
       (i przypisz je do `result`)
    3. Użyj `map()` aby podnieść wszystkie liczby w `result` do sześcianu
    4. Stwórz `result: float` ze średnią arytmetyczną z `result`
    5. Nie używaj wyrażeń lambda
    6. Zwróć uwagę, że cały czas pracujesz na jednym strumieniu danych
    7. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * type cast to `list()` to expand generator before calculating mean
    * `mean = sum(...) / len(...)`
    * TypeError: object of type 'map' has no len()
    * ZeroDivisionError: division by zero

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

    >>> isfunction(odd)
    True
    >>> isfunction(cube)
    True
    >>> type(result) is float
    True
    >>> result
    245.0
"""

def odd(x):
    return x % 2


def cube(x):
    return x ** 3


# Range numbers from 0 to 10 (exclusive)
# Filter odd numbers
# Cube result
# Calculate mean
# type: float
result = ...