{:check ["true"]}
A common pattern is to update some state value during the iteration of a list.
xs = [1,2,3,4,5]
total = 0
for x in xs:
total = total + x
This is known as the reduce pattern, in which the list xs
is
reduced to total
.
This can be visualized as follows:
0 + 1 + 2 + 3 ...
--- --- ---------------------
| | |
| | |
| | +---- the sequence of elements
| |
initial +--- state update function
value (known as the reducer)
So, the reduce pattern can be completely characterized by:
Python provides a higher order function functools.reduce
to
perform reduce.
from functools import reduce
def reduce_fn(x, y):
return x + y
total = reduce(reduce_fn, [1,2,3,4,5], 0)
Reduce without initial state value
Sometimes, we don't need to explicitly provide the initial state value as the first element in the sequence can be used as the initial state value.
1 + 2 + 3 + 4 ...
--- ---
-|----|------------------------
| | |
| | |
| | +---- the sequence of elements
| |
initial +--- reducer
value
The initial value for functools.reduce
is optional.
from functools import reduce
def reduce_fn(x, y):
return x + y
total = reduce(reduce_fn, [1,2,3,4,5])
We can compute the sum of all positive elements in a list of numbers.
split=7
def f(state, x): return (state + x) if x > 0 else state xs = [1, -1, 3, 2, -2, -10, 1] reduce(f, xs)
xs = [1, -1, 3, 2, -2, -10, 1] total = 0 for x in xs: if x > 0: total += x
We can compute the maximum value of a list of numbers.
xs = [1, -1, 3, 2, -2, -10, 1]
reduce(max, xs)
Suppose that we are working with a list of dictionaries.
students = [
{"name": "Jack", "age": 20, "grade": 90},
{"name": "Jill", "age": 18, "grade": 89},
{"name": "Joe", "age": 19, "grade": 83}
]
We might want to get the age range:
{
min_age: 18,
max_age: 20
}
We need to design the reducer function:
def f(state, student):
if state is None:
state = {
'min_age': student['age'],
'max_age': student['age']
}
else:
state['min_age'] = min(state['min_age'], student['age'])
state['max_age'] = max(state['max_age'], student['age'])
return state
Viola, we can quickly get the range of students' age using reduce:
reduce(f, students, None)