6.11. Idiom Reduce

  • Reduce sequence using function

  • Built-in

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

6.11.1. Syntax

6.11.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

6.11.3. Solution

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

6.11.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

6.11.5. Map Reduce

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

6.11.6. Assignments

Code 6.41. Solution
"""
* Assignment: Idiom Reduce Evaluate
* Type: class assignment
* Complexity: easy
* Lines of code: 2 lines
* Time: 3 min

English:
    1. Define `result: int` with sum of `DATA`
    2. Note, that all the time you are working on a data stream
    3. Use reduce()
    4. Run doctests - all must succeed

Polish:
    1. Zdefiniuj `result: int` ze sumą z `DATA`
    2. Zwróć uwagę, że cały czas pracujesz na strumieniu danych
    3. Użyj reduce()
    4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * from functools import reduce

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

    >>> result
    1225
"""

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 sum of DATA
# Use reduce()
# type: int
result = ...

Code 6.42. Solution
"""
* Assignment: Idiom Reduce Chain
* Complexity: easy
* Lines of code: 2 lines
* Time: 3 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

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

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


Code 6.43. Solution
"""
* Assignment: Idiom Reduce Impl
* Complexity: medium
* Lines of code: 4 lines
* Time: 13 min

English:
    1. Write own implementation of a built-in `reduce()` function
    2. Define function `myreduce` with parameters:
        a. parameter `function: Callable`
        b. parameter `iterable: list | tuple`
    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: map, filter, zip, enumerate, all, any, reduce
    5. Run doctests - all must succeed

Polish:
    1. Zaimplementuj własne rozwiązanie wbudowanej funkcji `reduce()`
    2. Zdefiniuj funkcję `myreduce` z parametrami:
        a. parameter `function: Callable`
        b. parameter `iterable: list | tuple`
    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: map, filter, zip, enumerate, all, any, reduce
    5. Uruchom doctesty - wszystkie muszą się powieść

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from inspect import isfunction
    >>> from operator import add, mul
    >>> assert isfunction(myreduce)

    >>> myreduce(add, [1, 2, 3, 4, 5])
    15

    >>> myreduce(mul, [1, 2, 3, 4, 5])
    120
"""

# Write own implementation of a built-in `reduce()` function
# Define function `myrange` with parameters: `function`, `iterable`
# type: Callable[[Callable, Iterable], Any]
def myreduce(function, iterable):
    ...