VPython MapReduceFilter: Difference between revisions
Kkluesner3 (talk | contribs) No edit summary |
Sabrinayang (talk | contribs) No edit summary |
||
| Line 1: | Line 1: | ||
'''<big>Sabrina Yang - Spring 2026</big>''' | |||
== '''Introduction''' == | == '''Introduction''' == | ||
In Python, map, | In Python, <code>map()</code>, <code>filter()</code>, and <code>reduce()</code> are | ||
known as '''higher-order functions'''. Higher-order functions are functions that take other functions as arguments. | |||
These functions are especially valuable. | |||
A typical simulation can include hundreds of objects and variables that each operate under the same physics laws. Instead of writing | |||
for loops to iterate through each object, <code>map()</code>, <code>filter()</code>, | |||
and <code>reduce()</code> handles the iteration automatically, which makes the code shorter and more efficient. | |||
The three functions each serve a its own role: | |||
* <code>map()</code>: '''transforms''' every element in a list by applying a function to it | |||
* <code>filter()</code>: '''selects''' a subset of elements that satisfy a condition | |||
* <code>reduce()</code>: '''aggregates''' all elements into a single accumulated value | |||
'''Important note for Python 3:''' <code>map()</code> and <code>filter()</code> return | |||
lazy iterator objects, in other words objects that don't do any work until you ask it for the results, rather than lists. This means they do not compute anything until | |||
you actually need the values. Wrap them in <code>list()</code> to force evaluation and | |||
get a plain list back. <code>reduce()</code> was removed from Python 3's built-ins and | |||
must be explicitly imported: | |||
from functools import reduce | |||
'''Important note for GlowScript VPython:''' GlowScript runs a restricted subset of | |||
Python and does not support lambda expressions or the <code>functools</code> module. | |||
Use named <code>def</code> functions instead of lambdas, and implement | |||
<code>reduce()</code> manually as shown in the interactive simulation section below. | |||
---- | |||
== '''Background: Functional Programming''' == | |||
To fully understand <code>map()</code>, <code>filter()</code>, and <code>reduce()</code>, | |||
you need to understand first-class functions. In Python, all functions | |||
are first class objects, meaning they can be: | |||
* Assigned to variables | |||
* Passed as arguments to other functions | |||
* Returned as values from other functions | |||
This is what makes higher-order functions possible. When you write | |||
<code>map(calc_weight, masses)</code>, you are passing the function | |||
<code>calc_weight</code> itself as an argument to | |||
<code>map()</code>. <code>map()</code> then calls <code>calc_weight</code> | |||
for each element. | |||
---- | |||
== '''Lambda Expressions''' == | |||
A '''lambda expression''' is a function you write in one line without giving it a name. The syntax is: | |||
lambda <parameters>: <expression> | |||
The function exists only at the point where | |||
it is used. These two definitions produce the same results: | |||
# Traditional way | |||
def square(x): | |||
return x**2 | |||
# Using lambda | |||
square = lambda x: x**2 | |||
Lambdas save you from having to define a whole separate function when you only need it once: | |||
# Without lambda: requires a function defined somewhere else | |||
result = list(map(square, [1, 2, 3, 4])) | |||
# With lambda: no defined function needed | |||
result = list(map(lambda x: x**2, [1, 2, 3, 4])) | |||
# Result: [1, 4, 9, 16] | |||
Lambda expressions can also take multiple parameters, which is useful for | |||
<code>reduce()</code>: | |||
from functools import reduce | |||
total = reduce(lambda acc, x: acc + x, [1, 2, 3, 4], 0) | |||
# Result: 10 | |||
'''When to use lambdas vs def:''' | |||
* Use a lambda when the function is short, used only once, and | |||
passed directly as an argument | |||
* Use <code>def</code> when the function is longer than one line or reused constantly | |||
'''GlowScript limitation:''' Lambda expressions are not supported in GlowScript VPython. | |||
Always use named <code>def</code> functions when writing code for Trinket or | |||
GlowScript. | |||
---- | ---- | ||
== '''Inputs and Type Matching''' == | |||
All three functions share the same basic calling convention: | |||
higher_order_function(function, iterable) | |||
The '''function''' argument describes the operation to perform. The '''iterable''' | |||
argument is the sequence of data to operate on, which can be a list, tuple, range, | |||
or any other iterable Python object. | |||
One important constraint is '''type matching''': the function must be able to accept | |||
the types contained in the iterable. For example, if your list contains floating-point | |||
numbers, your function must expect floats. Mismatches will cause a <code>TypeError</code> | |||
at runtime. | |||
Example using a named function: | |||
def cubed(x): | |||
return x**3 | |||
items = [1, 2, 3, 4] | |||
result = list(map(cubed, items)) | |||
# Result: [1, 8, 27, 64] | |||
The | The same using a lambda: | ||
items = [1, 2, 3, 4] | |||
result = list(map(lambda x: x**3, items)) | |||
# Result: [1, 8, 27, 64] | |||
You can also pass Python's built-in functions directly: | |||
words = ['hello', 'world', 'vpython'] | |||
lengths = list(map(len, words)) | |||
# Result: [5, 5, 7] | |||
---- | |||
== '''Map()''' == | == '''Map()''' == | ||
=== How it works === | |||
<code>map(function, iterable)</code> applies a function to '''every element''' of an | |||
iterable and returns an iterator of the results. The original list is never modified. Instead, | |||
a new sequence of transformed values is produced. The output always has the same number | |||
of elements as the input. | |||
map(function, iterable) | |||
For a list <code>[a, b, c, d]</code> and a function <code>f</code>: | |||
map(f, [a, b, c, d]) → [f(a), f(b), f(c), f(d)] | |||
=== Basic example === | |||
numlist = [1, 2, 3, 4, 5] | |||
result = list(map(lambda x: x * 2, numlist)) | |||
# Result: [2, 4, 6, 8, 10] | |||
=== Examples using Physics === | |||
'''Computing gravitational weight (F = mg) for a set of masses:''' | |||
g = 9.8 # m/s^2 | |||
masses = [0.5, 1.0, 2.5, 5.0, 10.0] # kg | |||
weights = list(map(lambda m: m * g, masses)) | |||
# Result: [4.9, 9.8, 24.5, 49.0, 98.0] Newtons | |||
'''Computing kinetic energy (KE = ½mv²) for a set of velocities:''' | |||
mass = 2.0 # kg | |||
velocities = [3.0, 5.5, 2.1, 8.0] # m/s | |||
ke_list = list(map(lambda v: 0.5 * mass * v**2, velocities)) | |||
# Result: [9.0, 30.25, 4.41, 64.0] Joules | |||
'''Converting a list of temperatures from Celsius to Kelvin:''' | |||
temps_C = [0, 20, 37, 100, -273.15] | |||
temps_K = list(map(lambda T: T + 273.15, temps_C)) | |||
# Result: [273.15, 293.15, 310.15, 373.15, 0.0] Kelvin | |||
=== Why use map() instead of a for-loop? === | |||
Both of the following produce the same result, but <code>map()</code> is shorter, and expresses the point more directly: | |||
# For-loop approach | |||
weights = [] | |||
for m in masses: | |||
weights.append(m * 9.8) | |||
# map() approach — same result, fewer lines | |||
weights = list(map(lambda m: m * 9.8, masses)) | |||
---- | |||
== '''Filter()''' == | == '''Filter()''' == | ||
=== How it works === | |||
<code>filter(function, iterable)</code> keeps only the elements for which the function | |||
returns <code>True</code>. The function must return a boolean value (or a value Python | |||
treats as truthy or falsy). The output list may be shorter than the input list. | |||
filter(function, iterable) | |||
filter(lambda x: condition, iterable) | |||
Conceptually, for a list <code>[a, b, c, d]</code> and a predicate function | |||
<code>p</code>: | |||
filter(p, [a, b, c, d]) → [x for x in [a,b,c,d] if p(x) is True] | |||
=== Basic example === | |||
numbers = [3, 7, 5, 2, 1, 6] | |||
result = list(filter(lambda x: x > 3, numbers)) | |||
# Result: [7, 5, 6] | |||
=== Physics examples === | |||
'''Isolating particles moving above a speed threshold:''' | |||
speeds = [120, 340, 95, 500, 210, 80] # m/s | |||
fast_particles = list(filter(lambda v: v > 200, speeds)) | |||
# Result: [340, 500, 210] | |||
'''Keeping only positive charges from a mixed list:''' | |||
charges = [-1.6e-19, 1.6e-19, -3.2e-19, 3.2e-19, 0, 1.6e-19] # Coulombs | |||
positive = list(filter(lambda q: q > 0, charges)) | |||
# Result: [1.6e-19, 3.2e-19, 1.6e-19] | |||
'''Filtering out particles that have left the simulation boundary:''' | |||
# Each particle p has a .pos.x attribute representing its x position | |||
boundary = 10.0 # meters | |||
inside = list(filter(lambda p: abs(p.pos.x) < boundary, particles)) | |||
=== Passing None as the function === | |||
A special case: passing <code>None</code> instead of a function removes all | |||
false values from the list (zeros, empty strings, <code>None</code>, <code>False</code>): | |||
messy = [1, 0, 3, None, 5, 0, 7] | |||
clean = list(filter(None, messy)) | |||
# Result: [1, 3, 5, 7] | |||
---- | |||
== '''Reduce()''' == | == '''Reduce()''' == | ||
=== How it works === | |||
<code>reduce(function, iterable, initializer)</code> '''cumulatively''' applies a | |||
two-argument function to the elements of a list, reducing the entire sequence down | |||
to a single scalar value. | |||
The function passed to <code>reduce()</code> must accept exactly two arguments: | |||
* The '''accumulator''' — the running result | |||
* The '''current element''' — the next item from the list | |||
After each call, the return value becomes the new accumulator for the next call. | |||
from functools import reduce | |||
reduce(function, iterable, initializer) | |||
=== Step-by-step walkthrough === | |||
from functools import reduce | |||
numbers = [1, 2, 3, 4] | |||
result = reduce(lambda x, y: x * y, numbers) | |||
# Step 1: x=1, y=2 → 1 * 2 = 2 | |||
# Step 2: x=2, y=3 → 2 * 3 = 6 | |||
# Step 3: x=6, y=4 → 6 * 4 = 24 | |||
# Final result: 24 | |||
=== Physics examples === | |||
'''Adding all masses in a system:''' | |||
from functools import reduce | |||
masses = [1.0, 2.0, 3.0, 4.0] # kg | |||
total_mass = reduce(lambda acc, m: acc + m, masses, 0.0) | |||
# Result: 10.0 kg | |||
'''Finding the maximum speed in a list of particles:''' | |||
from functools import reduce | |||
speeds = [3.2, 7.8, 1.1, 9.4, 5.5] # m/s | |||
max_speed = reduce(lambda a, b: a if a > b else b, speeds) | |||
# Result: 9.4 m/s | |||
'''Computing total work done by forces over different displacements (W = F·d):''' | |||
from functools import reduce | |||
forces = [10.0, 25.0, 5.0, 40.0] # Newtons | |||
displacements = [2.0, 1.5, 3.0, 0.5] # meters | |||
work_list = list(map(lambda fd: fd[0] * fd[1], zip(forces, displacements))) | |||
total_work = reduce(lambda acc, w: acc + w, work_list, 0.0) | |||
# Result: 20.0 + 37.5 + 15.0 + 20.0 = 92.5 Joules | |||
=== Important warning === | |||
Always provide an initializer (third argument) when using <code>reduce()</code>. | |||
Calling it on an empty list without an initializer raises a <code>TypeError</code>. | |||
With an initializer, an empty list returns the initializer value: | |||
reduce(lambda acc, x: acc + x, [], 0.0) | |||
# Returns 0.0 safely instead of raising an error | |||
---- | |||
== ''' | == '''Combining map(), filter(), and reduce()''' == | ||
The power of these functions come from chaining them together into a | |||
data pipeline. Each function's output becomes the next function's input, creating | |||
a clean sequence of transformation → selection → aggregation. | |||
'''Example — total kinetic energy of only the fast-moving particles in a system:''' | |||
from functools import reduce | |||
# Step 1: filter() — only keep particles with a speed greater than 3 m/s | |||
moving = list(filter(lambda p: p.speed > 3.0, particles)) | |||
# Step 2: map() — calculate the kinetic energy for each particle | |||
ke_list = list(map(lambda p: 0.5 * p.mass * p.speed**2, moving)) | |||
# Step 3: reduce() — add all the kinetic energies | |||
total_ke = reduce(lambda acc, ke: acc + ke, ke_list, 0.0) | |||
print("Total KE of fast particles:", round(total_ke, 2), "J") | |||
This three-step pattern (filter, map, reduce) is one of the most widely used patterns in programming. | |||
---- | |||
== '''Interactive Simulation''' == | |||
The following GlowScript simulation demonstrates all three functions working | |||
together in a physics context: | |||
[https://trinket.io/glowscript/9e53d57b352f map(), filter(), and reduce() in VPython Physics — Trinket] | |||
The simulation creates five spheres arranged in a horizontal row, each assigned a | |||
different mass (ranging from 1 to 8 kg) and a different speed (ranging from 1.5 to | |||
6 m/s). The radius of each sphere is proportional to its mass. | |||
The program then demonstrates each function in sequence: | |||
* '''map()''' iterates over the list of masses and computes the gravitational weight | |||
of each sphere using Newton's second law (F = mg, with g = 9.8 m/s²). The results | |||
are printed to the console, showing the weight in Newtons for each sphere. | |||
* '''filter()''' checks every sphere's speed and keeps only those moving faster than | |||
3.0 m/s. Those spheres are turned '''red''' in the 3D scene, providing a visual | |||
indicator of which objects meet the threshold condition. The speeds of the selected | |||
spheres are also printed. | |||
* '''reduce()''' — implemented manually as a custom function since GlowScript does | |||
not support the <code>functools</code> module. It adds the kinetic energy of every sphere into a single total. The individual kinetic energies | |||
and the system total are printed to the console. | |||
Together, the simulation illustrates the filter → map → reduce pipeline in a | |||
physical setting, showing how the three functions complement each other. | |||
---- | |||
== '''References''' == | == '''References''' == | ||
[http://www.bogotobogo.com/python/python_fncs_map_filter_reduce.php] | |||
[http://book.pythontips.com/en/latest/map_filter.html] | [http://www.bogotobogo.com/python/python_fncs_map_filter_reduce.php 1. Python map, filter, reduce — bogotobogo.com] | ||
[http://vpython.org/contents/docs/VisualIntro.html] | |||
[http://book.pythontips.com/en/latest/map_filter.html 2. Map, Filter — Python Tips] | |||
[http://vpython.org/contents/docs/VisualIntro.html 3. VPython Documentation — vpython.org] | |||
[https://docs.python.org/3/library/functions.html 4. Python 3 Built-in Functions (map, filter) — Python Software Foundation] | |||
[https://docs.python.org/3/library/functools.html 5. functools module (reduce) — Python Software Foundation] | |||
[https://docs.python.org/3/howto/functional.html 6. Functional Programming HOWTO — Python Software Foundation] | |||
[https://realpython.com/python-map-function/ 7. Python's map() — Real Python] | |||
[https://realpython.com/python-filter-function/ 8. Python's filter() — Real Python] | |||
[https://realpython.com/python-reduce-function/ 9. Python's reduce() — Real Python] | |||
[https://realpython.com/python-lambda/ 10. Lambda Expressions in Python — Real Python] | |||
[https://www.geeksforgeeks.org/functional-programming-in-python/ 11. Functional Programming in Python — GeeksforGeeks] | |||
[https://www.geeksforgeeks.org/higher-order-functions-in-python/ 12. Higher-Order Functions in Python — GeeksforGeeks] | |||
[https://www.glowscript.org 13. GlowScript VPython — Official Site] | |||
[https://trinket.io/glowscript 14. GlowScript on Trinket] | |||
[https://vpython.org 15. VPython Official Documentation] | |||
Revision as of 19:13, 26 April 2026
Sabrina Yang - Spring 2026
Introduction
In Python, map(), filter(), and reduce() are
known as higher-order functions. Higher-order functions are functions that take other functions as arguments.
These functions are especially valuable.
A typical simulation can include hundreds of objects and variables that each operate under the same physics laws. Instead of writing
for loops to iterate through each object, map(), filter(),
and reduce() handles the iteration automatically, which makes the code shorter and more efficient.
The three functions each serve a its own role:
map(): transforms every element in a list by applying a function to itfilter(): selects a subset of elements that satisfy a conditionreduce(): aggregates all elements into a single accumulated value
Important note for Python 3: map() and filter() return
lazy iterator objects, in other words objects that don't do any work until you ask it for the results, rather than lists. This means they do not compute anything until
you actually need the values. Wrap them in list() to force evaluation and
get a plain list back. reduce() was removed from Python 3's built-ins and
must be explicitly imported:
from functools import reduce
Important note for GlowScript VPython: GlowScript runs a restricted subset of
Python and does not support lambda expressions or the functools module.
Use named def functions instead of lambdas, and implement
reduce() manually as shown in the interactive simulation section below.
Background: Functional Programming
To fully understand map(), filter(), and reduce(),
you need to understand first-class functions. In Python, all functions
are first class objects, meaning they can be:
- Assigned to variables
- Passed as arguments to other functions
- Returned as values from other functions
This is what makes higher-order functions possible. When you write
map(calc_weight, masses), you are passing the function
calc_weight itself as an argument to
map(). map() then calls calc_weight
for each element.
Lambda Expressions
A lambda expression is a function you write in one line without giving it a name. The syntax is:
lambda <parameters>: <expression>
The function exists only at the point where it is used. These two definitions produce the same results:
# Traditional way
def square(x):
return x**2
# Using lambda
square = lambda x: x**2
Lambdas save you from having to define a whole separate function when you only need it once:
# Without lambda: requires a function defined somewhere else result = list(map(square, [1, 2, 3, 4])) # With lambda: no defined function needed result = list(map(lambda x: x**2, [1, 2, 3, 4])) # Result: [1, 4, 9, 16]
Lambda expressions can also take multiple parameters, which is useful for
reduce():
from functools import reduce total = reduce(lambda acc, x: acc + x, [1, 2, 3, 4], 0) # Result: 10
When to use lambdas vs def:
- Use a lambda when the function is short, used only once, and
passed directly as an argument
- Use
defwhen the function is longer than one line or reused constantly
GlowScript limitation: Lambda expressions are not supported in GlowScript VPython.
Always use named def functions when writing code for Trinket or
GlowScript.
Inputs and Type Matching
All three functions share the same basic calling convention:
higher_order_function(function, iterable)
The function argument describes the operation to perform. The iterable argument is the sequence of data to operate on, which can be a list, tuple, range, or any other iterable Python object.
One important constraint is type matching: the function must be able to accept
the types contained in the iterable. For example, if your list contains floating-point
numbers, your function must expect floats. Mismatches will cause a TypeError
at runtime.
Example using a named function:
def cubed(x):
return x**3
items = [1, 2, 3, 4]
result = list(map(cubed, items))
# Result: [1, 8, 27, 64]
The same using a lambda:
items = [1, 2, 3, 4] result = list(map(lambda x: x**3, items)) # Result: [1, 8, 27, 64]
You can also pass Python's built-in functions directly:
words = ['hello', 'world', 'vpython'] lengths = list(map(len, words)) # Result: [5, 5, 7]
Map()
How it works
map(function, iterable) applies a function to every element of an
iterable and returns an iterator of the results. The original list is never modified. Instead,
a new sequence of transformed values is produced. The output always has the same number
of elements as the input.
map(function, iterable)
For a list [a, b, c, d] and a function f:
map(f, [a, b, c, d]) → [f(a), f(b), f(c), f(d)]
Basic example
numlist = [1, 2, 3, 4, 5] result = list(map(lambda x: x * 2, numlist)) # Result: [2, 4, 6, 8, 10]
Examples using Physics
Computing gravitational weight (F = mg) for a set of masses:
g = 9.8 # m/s^2 masses = [0.5, 1.0, 2.5, 5.0, 10.0] # kg weights = list(map(lambda m: m * g, masses)) # Result: [4.9, 9.8, 24.5, 49.0, 98.0] Newtons
Computing kinetic energy (KE = ½mv²) for a set of velocities:
mass = 2.0 # kg velocities = [3.0, 5.5, 2.1, 8.0] # m/s ke_list = list(map(lambda v: 0.5 * mass * v**2, velocities)) # Result: [9.0, 30.25, 4.41, 64.0] Joules
Converting a list of temperatures from Celsius to Kelvin:
temps_C = [0, 20, 37, 100, -273.15] temps_K = list(map(lambda T: T + 273.15, temps_C)) # Result: [273.15, 293.15, 310.15, 373.15, 0.0] Kelvin
Why use map() instead of a for-loop?
Both of the following produce the same result, but map() is shorter, and expresses the point more directly:
# For-loop approach
weights = []
for m in masses:
weights.append(m * 9.8)
# map() approach — same result, fewer lines
weights = list(map(lambda m: m * 9.8, masses))
Filter()
How it works
filter(function, iterable) keeps only the elements for which the function
returns True. The function must return a boolean value (or a value Python
treats as truthy or falsy). The output list may be shorter than the input list.
filter(function, iterable) filter(lambda x: condition, iterable)
Conceptually, for a list [a, b, c, d] and a predicate function
p:
filter(p, [a, b, c, d]) → [x for x in [a,b,c,d] if p(x) is True]
Basic example
numbers = [3, 7, 5, 2, 1, 6] result = list(filter(lambda x: x > 3, numbers)) # Result: [7, 5, 6]
Physics examples
Isolating particles moving above a speed threshold:
speeds = [120, 340, 95, 500, 210, 80] # m/s fast_particles = list(filter(lambda v: v > 200, speeds)) # Result: [340, 500, 210]
Keeping only positive charges from a mixed list:
charges = [-1.6e-19, 1.6e-19, -3.2e-19, 3.2e-19, 0, 1.6e-19] # Coulombs positive = list(filter(lambda q: q > 0, charges)) # Result: [1.6e-19, 3.2e-19, 1.6e-19]
Filtering out particles that have left the simulation boundary:
# Each particle p has a .pos.x attribute representing its x position boundary = 10.0 # meters inside = list(filter(lambda p: abs(p.pos.x) < boundary, particles))
Passing None as the function
A special case: passing None instead of a function removes all
false values from the list (zeros, empty strings, None, False):
messy = [1, 0, 3, None, 5, 0, 7] clean = list(filter(None, messy)) # Result: [1, 3, 5, 7]
Reduce()
How it works
reduce(function, iterable, initializer) cumulatively applies a
two-argument function to the elements of a list, reducing the entire sequence down
to a single scalar value.
The function passed to reduce() must accept exactly two arguments:
- The accumulator — the running result
- The current element — the next item from the list
After each call, the return value becomes the new accumulator for the next call.
from functools import reduce reduce(function, iterable, initializer)
Step-by-step walkthrough
from functools import reduce numbers = [1, 2, 3, 4] result = reduce(lambda x, y: x * y, numbers) # Step 1: x=1, y=2 → 1 * 2 = 2 # Step 2: x=2, y=3 → 2 * 3 = 6 # Step 3: x=6, y=4 → 6 * 4 = 24 # Final result: 24
Physics examples
Adding all masses in a system:
from functools import reduce masses = [1.0, 2.0, 3.0, 4.0] # kg total_mass = reduce(lambda acc, m: acc + m, masses, 0.0) # Result: 10.0 kg
Finding the maximum speed in a list of particles:
from functools import reduce speeds = [3.2, 7.8, 1.1, 9.4, 5.5] # m/s max_speed = reduce(lambda a, b: a if a > b else b, speeds) # Result: 9.4 m/s
Computing total work done by forces over different displacements (W = F·d):
from functools import reduce forces = [10.0, 25.0, 5.0, 40.0] # Newtons displacements = [2.0, 1.5, 3.0, 0.5] # meters work_list = list(map(lambda fd: fd[0] * fd[1], zip(forces, displacements))) total_work = reduce(lambda acc, w: acc + w, work_list, 0.0) # Result: 20.0 + 37.5 + 15.0 + 20.0 = 92.5 Joules
Important warning
Always provide an initializer (third argument) when using reduce().
Calling it on an empty list without an initializer raises a TypeError.
With an initializer, an empty list returns the initializer value:
reduce(lambda acc, x: acc + x, [], 0.0) # Returns 0.0 safely instead of raising an error
Combining map(), filter(), and reduce()
The power of these functions come from chaining them together into a data pipeline. Each function's output becomes the next function's input, creating a clean sequence of transformation → selection → aggregation.
Example — total kinetic energy of only the fast-moving particles in a system:
from functools import reduce
# Step 1: filter() — only keep particles with a speed greater than 3 m/s
moving = list(filter(lambda p: p.speed > 3.0, particles))
# Step 2: map() — calculate the kinetic energy for each particle
ke_list = list(map(lambda p: 0.5 * p.mass * p.speed**2, moving))
# Step 3: reduce() — add all the kinetic energies
total_ke = reduce(lambda acc, ke: acc + ke, ke_list, 0.0)
print("Total KE of fast particles:", round(total_ke, 2), "J")
This three-step pattern (filter, map, reduce) is one of the most widely used patterns in programming.
Interactive Simulation
The following GlowScript simulation demonstrates all three functions working together in a physics context: map(), filter(), and reduce() in VPython Physics — Trinket
The simulation creates five spheres arranged in a horizontal row, each assigned a different mass (ranging from 1 to 8 kg) and a different speed (ranging from 1.5 to 6 m/s). The radius of each sphere is proportional to its mass.
The program then demonstrates each function in sequence:
- map() iterates over the list of masses and computes the gravitational weight
of each sphere using Newton's second law (F = mg, with g = 9.8 m/s²). The results are printed to the console, showing the weight in Newtons for each sphere.
- filter() checks every sphere's speed and keeps only those moving faster than
3.0 m/s. Those spheres are turned red in the 3D scene, providing a visual indicator of which objects meet the threshold condition. The speeds of the selected spheres are also printed.
- reduce() — implemented manually as a custom function since GlowScript does
not support the functools module. It adds the kinetic energy of every sphere into a single total. The individual kinetic energies
and the system total are printed to the console.
Together, the simulation illustrates the filter → map → reduce pipeline in a physical setting, showing how the three functions complement each other.
References
1. Python map, filter, reduce — bogotobogo.com
3. VPython Documentation — vpython.org
4. Python 3 Built-in Functions (map, filter) — Python Software Foundation
5. functools module (reduce) — Python Software Foundation
6. Functional Programming HOWTO — Python Software Foundation
7. Python's map() — Real Python
8. Python's filter() — Real Python
9. Python's reduce() — Real Python
10. Lambda Expressions in Python — Real Python
11. Functional Programming in Python — GeeksforGeeks
12. Higher-Order Functions in Python — GeeksforGeeks