VPython MapReduceFilter: Difference between revisions

From Physics Book
Jump to navigation Jump to search
No edit summary
No edit summary
Line 4: Line 4:


In Python, <code>map()</code>, <code>filter()</code>, and <code>reduce()</code> are  
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.  
known as higher-order functions. Higher-order functions are functions that  
These functions are especially valuable.
take other functions as arguments. A typical VPython simulation can have hundreds of  
A typical simulation can include hundreds of objects and variables that each operate under the same physics laws. Instead of writing  
objects that all follow the same physics equations, and writing for-loops to do the same
for loops to iterate through each object, <code>map()</code>, <code>filter()</code>,  
calculation over and over can be inefficient. <code>map()</code>,  
and <code>reduce()</code> handles the iteration automatically, which makes the code shorter and more efficient.
<code>filter()</code>, and <code>reduce()</code> take care of the for-loops,  
allowing you to focus on the point of the code itself.


The three functions each serve a its own role:
Each function does something different:
* <code>map()</code>: '''transforms''' every element in a list by applying a function to it
* <code>map()</code>: applies a function to every element in a list
* <code>filter()</code>: '''selects''' a subset of elements that satisfy a condition
* <code>filter()</code>: iterates through a list and only keeps the elements that meet a certain condition
* <code>reduce()</code>: '''aggregates''' all elements into a single accumulated value
* <code>reduce()</code>: takes a whole list and turns it into one single value


'''Important note for Python 3:''' <code>map()</code> and <code>filter()</code> return
'''Python 3 note:''' <code>map()</code> and <code>filter()</code> do not actually work until you ask for the results. Wrap them in <code>list()</code> to get
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
a list back. <code>reduce()</code> has to be imported before you can use it:
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
  from functools import reduce


'''Important note for GlowScript VPython:''' GlowScript runs a restricted subset of
'''GlowScript note:''' GlowScript does not support lambda expressions or the  
Python and does not support lambda expressions or the <code>functools</code> module.  
<code>functools</code> module. Use regular <code>def</code> functions instead of  
Use named <code>def</code> functions instead of lambdas, and implement
lambdas, and write <code>reduce()</code> yourself. Here is an example of this
<code>reduce()</code> manually as shown in the interactive simulation section below.
in the simulation section below.


----
----


== '''Background: Functional Programming''' ==
== '''Background''' ==


To fully understand <code>map()</code>, <code>filter()</code>, and <code>reduce()</code>,
In Python, functions are objects just like numbers or strings. That means you can:
you need to understand first-class functions. In Python, all functions  
* Store a function in a variable
are first class objects, meaning they can be:
* Pass a function into another function as an argument
* Assigned to variables
* Get a function back as a return value
* Passed as arguments to other functions
* Returned as values from other functions


This is what makes higher-order functions possible. When you write  
This is what makes <code>map()</code>, <code>filter()</code>, and <code>reduce()</code>
<code>map(calc_weight, masses)</code>, you are passing the function  
work. When you write <code>map(calc_weight, masses)</code>, you are passing the  
<code>calc_weight</code> itself as an argument to
function <code>calc_weight</code> itself into <code>map()</code>. Then
<code>map()</code>. <code>map()</code> then calls <code>calc_weight</code>  
<code>map()</code> runs it on every item in the list so you don't have to.
for each element.
 
There are a few reasons why writing code this way is efficient:
* '''It is easy to read:''' You can look at the code and immediately tell what it
is doing — like if you see "apply this formula to every mass" you just get it,
no decoding required
* '''Fewer bugs:''' Every time you write a for-loop you have to manually keep track of index
variables, which is easy to make mistakes on. These functions
handle the indices, so there is less room for errors.
* '''You can chain them:''' The output of <code>map()</code> can go straight into
<code>filter()</code> or <code>reduce()</code> without extra steps, which keeps
the variables clean and short.


----
----
Line 48: Line 54:
== '''Lambda Expressions''' ==
== '''Lambda Expressions''' ==


A '''lambda expression''' is a function you write in one line without giving it a name. The syntax is:
A '''lambda expression''' is a function you write in one line without giving it a name.  
The format is:


  lambda <parameters>: <expression>
  lambda <parameters>: <expression>


The function exists only at the point where  
The function only exists at the point where it is used. These two do the exact same thing:
it is used. These two definitions produce the same results:


  # Traditional way
  # Regular way
  def square(x):
  def square(x):
     return x**2
     return x**2
   
   
  # Using lambda
  # Lambda way
  square = lambda x: x**2
  square = lambda x: x**2


Lambdas save you from having to define a whole separate function when you only need it once:
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
  # Without lambda: needs a function defined somewhere else
  result = list(map(square, [1, 2, 3, 4]))
  result = list(map(square, [1, 2, 3, 4]))
   
   
  # With lambda: no defined function needed
  # With lambda: no separate function needed
  result = list(map(lambda x: x**2, [1, 2, 3, 4]))
  result = list(map(lambda x: x**2, [1, 2, 3, 4]))
  # Result: [1, 4, 9, 16]
  # Result: [1, 4, 9, 16]


Lambda expressions can also take multiple parameters, which is useful for
They can also take two inputs, which comes up when using <code>reduce()</code>:
<code>reduce()</code>:


  from functools import reduce
  from functools import reduce
Line 78: Line 84:
  # Result: 10
  # Result: 10


'''When to use lambdas vs def:'''
'''Lambda vs def — when to use which:'''
* Use a lambda when the function is short, used only once, and  
* Use a lambda when the function is short, only needed once, and passed right
passed directly as an argument
into another function
* Use <code>def</code> when the function is longer than one line or reused constantly
* Use <code>def</code> when the function is longer or used in multiple places


'''GlowScript limitation:''' Lambda expressions are not supported in GlowScript VPython.  
'''GlowScript note:''' Lambdas do not work in GlowScript at all. Always use  
Always use named <code>def</code> functions when writing code for Trinket or
<code>def</code> when writing code for Trinket.
GlowScript.


----
----
Line 91: Line 96:
== '''Inputs and Type Matching''' ==
== '''Inputs and Type Matching''' ==


All three functions share the same basic calling convention:
All three functions follow the same basic structure:


  higher_order_function(function, iterable)
  function_name(function, list)


The '''function''' argument describes the operation to perform. The '''iterable'''
The first argument is the function you want to use. The second is the list of  
argument is the sequence of data to operate on, which can be a list, tuple, range,
data you want to run it on, which can be a list, tuple, etc.
or any other iterable Python object.


One important constraint is '''type matching''': the function must be able to accept
One thing to watch out for: the function has to be able to work with any item
the types contained in the iterable. For example, if your list contains floating-point
is in the list. If your list has decimal numbers but your function expects
numbers, your function must expect floats. Mismatches will cause a <code>TypeError</code>
whole numbers, Python will throw an error.
at runtime.


Example using a named function:
Example using a named function:
Line 112: Line 115:
  # Result: [1, 8, 27, 64]
  # Result: [1, 8, 27, 64]


The same using a lambda:
The same thing with a lambda:
  items = [1, 2, 3, 4]
  items = [1, 2, 3, 4]
  result = list(map(lambda x: x**3, items))
  result = list(map(lambda x: x**3, items))
  # Result: [1, 8, 27, 64]
  # Result: [1, 8, 27, 64]


You can also pass Python's built-in functions directly:
You can also pass Python's built-in functions straight in:
  words = ['hello', 'world', 'vpython']
  words = ['hello', 'world', 'vpython']
  lengths = list(map(len, words))
  lengths = list(map(len, words))
Line 128: Line 131:
=== How it works ===
=== How it works ===


<code>map(function, iterable)</code> applies a function to '''every element''' of an
<code>map(function, list)</code> runs a function on every single element in a list
iterable and returns an iterator of the results. The original list is never modified. Instead,
and gives you back all the results. The original list stays the same; you get a
a new sequence of transformed values is produced. The output always has the same number
new list of updated values.
of elements as the input.


  map(function, iterable)
  map(function, list)


For a list <code>[a, b, c, d]</code> and a function <code>f</code>:
So for a list <code>[a, b, c, d]</code> and some function <code>f</code>:
  map(f, [a, b, c, d])  →  [f(a), f(b), f(c), f(d)]
  map(f, [a, b, c, d])  →  [f(a), f(b), f(c), f(d)]


Line 144: Line 146:
  # Result: [2, 4, 6, 8, 10]
  # Result: [2, 4, 6, 8, 10]


=== Examples using Physics ===
=== Physics examples ===


'''Computing gravitational weight (F = mg) for a set of masses:'''
'''Gravitational weight (F = mg) for the masses:'''
  g = 9.8  # m/s^2
  g = 9.8  # m/s^2
  masses = [0.5, 1.0, 2.5, 5.0, 10.0]  # kg
  masses = [0.5, 1.0, 2.5, 5.0, 10.0]  # kg
Line 153: Line 155:
  # Result: [4.9, 9.8, 24.5, 49.0, 98.0]  Newtons
  # Result: [4.9, 9.8, 24.5, 49.0, 98.0]  Newtons


'''Computing kinetic energy (KE = ½mv²) for a set of velocities:'''
'''Kinetic energy of the velocities:'''
  mass = 2.0  # kg
  mass = 2.0  # kg
  velocities = [3.0, 5.5, 2.1, 8.0]  # m/s
  velocities = [3.0, 5.5, 2.1, 8.0]  # m/s
Line 160: Line 162:
  # Result: [9.0, 30.25, 4.41, 64.0]  Joules
  # Result: [9.0, 30.25, 4.41, 64.0]  Joules


'''Converting a list of temperatures from Celsius to Kelvin:'''
'''Converting temperature from Celsius to Kelvin:'''
  temps_C = [0, 20, 37, 100, -273.15]
  temps_C = [0, 20, 37, 100, -273.15]
  temps_K = list(map(lambda T: T + 273.15, temps_C))
  temps_K = list(map(lambda T: T + 273.15, temps_C))
  # Result: [273.15, 293.15, 310.15, 373.15, 0.0]  Kelvin
  # Result: [273.15, 293.15, 310.15, 373.15, 0.0]  Kelvin


=== Why use map() instead of a for-loop? ===
=== map() vs a for-loop ===


Both of the following produce the same result, but <code>map()</code> is shorter, and expresses the point more directly:
Both of these give the same answer, but <code>map()</code> is more concise:


  # For-loop approach
  # For-loop
  weights = []
  weights = []
  for m in masses:
  for m in masses:
     weights.append(m * 9.8)
     weights.append(m * 9.8)
   
   
  # map() approach — same result, fewer lines
  # map() — same thing in one line
  weights = list(map(lambda m: m * 9.8, masses))
  weights = list(map(lambda m: m * 9.8, masses))


Line 183: Line 185:
=== How it works ===
=== How it works ===


<code>filter(function, iterable)</code> keeps only the elements for which the function  
<code>filter(function, list)</code> iterates through a list and only keeps the elements  
returns <code>True</code>. The function must return a boolean value (or a value Python
where the function returns <code>True</code>.  
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
filter(function, list)
<code>p</code>:
  filter(lambda x: condition, list)
  filter(p, [a, b, c, d])  →  [x for x in [a,b,c,d] if p(x) is True]


=== Basic example ===
=== Example ===


  numbers = [3, 7, 5, 2, 1, 6]
  numbers = [3, 7, 5, 2, 1, 6]
Line 202: Line 199:
=== Physics examples ===
=== Physics examples ===


'''Isolating particles moving above a speed threshold:'''
'''Retrieving only the fastest particles:'''
  speeds = [120, 340, 95, 500, 210, 80]  # m/s
  speeds = [120, 340, 95, 500, 210, 80]  # m/s
   
   
Line 208: Line 205:
  # Result: [340, 500, 210]
  # Result: [340, 500, 210]


'''Keeping only positive charges from a mixed list:'''
'''Keeping the positive charges:'''
  charges = [-1.6e-19, 1.6e-19, -3.2e-19, 3.2e-19, 0, 1.6e-19]  # Coulombs
  charges = [-1.6e-19, 1.6e-19, -3.2e-19, 3.2e-19, 0, 1.6e-19]  # Coulombs
   
   
Line 214: Line 211:
  # Result: [1.6e-19, 3.2e-19, 1.6e-19]
  # Result: [1.6e-19, 3.2e-19, 1.6e-19]


'''Filtering out particles that have left the simulation boundary:'''
'''Removing particles that exited the simulation boundary:'''
  # Each particle p has a .pos.x attribute representing its x position
  # Each particle p has a .pos.x value for its x position
  boundary = 10.0  # meters
  boundary = 10.0  # meters
   
   
Line 222: Line 219:
=== Passing None as the function ===
=== Passing None as the function ===


A special case: passing <code>None</code> instead of a function removes all
If you pass <code>None</code> instead of a function, <code>filter()</code> removes  
false values from the list (zeros, empty strings, <code>None</code>, <code>False</code>):
every zero, empty string, <code>None</code>, and <code>False</code> from the list:


  messy = [1, 0, 3, None, 5, 0, 7]
  messy = [1, 0, 3, None, 5, 0, 7]
Line 235: Line 232:
=== How it works ===
=== How it works ===


<code>reduce(function, iterable, initializer)</code> '''cumulatively''' applies a  
<code>reduce(function, list, starting value)</code> takes a whole list and returns one single value. Unlike <code>map()</code>
two-argument function to the elements of a list, reducing the entire sequence down
and <code>filter()</code>, you do not get a list back — you get one number.
to a single scalar value.


The function passed to <code>reduce()</code> must accept exactly two arguments:
The function you pass in needs to take two inputs:
* The '''accumulator''' — the running result
* The running total so far
* The '''current element''' — the next item from the list
* The next item in the list


After each call, the return value becomes the new accumulator for the next call.
After each step, the result becomes the new total for the next step.


  from functools import reduce
  from functools import reduce
  reduce(function, iterable, initializer)
  reduce(function, list, starting value)


=== Step-by-step walkthrough ===
=== Step-by-step walkthrough ===
Line 261: Line 257:
=== Physics examples ===
=== Physics examples ===


'''Adding all masses in a system:'''
'''Adding up all the masses in a system:'''
  from functools import reduce
  from functools import reduce
   
   
Line 268: Line 264:
  # Result: 10.0 kg
  # Result: 10.0 kg


'''Finding the maximum speed in a list of particles:'''
'''Finding the fastest particle in a list:'''
  from functools import reduce
  from functools import reduce
   
   
Line 275: Line 271:
  # Result: 9.4 m/s
  # Result: 9.4 m/s


'''Computing total work done by forces over different displacements (W = F·d):'''
'''Total work done (W = F·d):'''
  from functools import reduce
  from functools import reduce
   
   
Line 285: Line 281:
  # Result: 20.0 + 37.5 + 15.0 + 20.0 = 92.5 Joules
  # Result: 20.0 + 37.5 + 15.0 + 20.0 = 92.5 Joules


=== Important warning ===
=== Watch out ===


Always provide an initializer (third argument) when using <code>reduce()</code>.  
Always give <code>reduce()</code> a starting value as the third argument. If the
Calling it on an empty list without an initializer raises a <code>TypeError</code>.
list is empty and there is no starting value, Python will crash. With a starting
With an initializer, an empty list returns the initializer value:
value, an empty list will give you that value back instead:


  reduce(lambda acc, x: acc + x, [], 0.0)
  reduce(lambda acc, x: acc + x, [], 0.0)
  # Returns 0.0 safely instead of raising an error
  # Returns 0.0 safely


----
----
Line 298: Line 294:
== '''Combining map(), filter(), and reduce()''' ==
== '''Combining map(), filter(), and reduce()''' ==


The power of these functions come from chaining them together into a
It is also efficient that functions can be chained together.
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:'''
'''Example: kinetic energy'''


  from functools import reduce
  from functools import reduce
   
   
  # Step 1: filter() — only keep particles with a speed greater than 3 m/s
  # Step 1: filter() — drop all values below 3.0 m/s
  moving = list(filter(lambda p: p.speed > 3.0, particles))
  moving = list(filter(lambda p: p.speed > 3.0, particles))
   
   
  # Step 2: map() — calculate the kinetic energy for each particle
  # Step 2: map() — calculate KE for each remaining particle
  ke_list = list(map(lambda p: 0.5 * p.mass * p.speed**2, moving))
  ke_list = list(map(lambda p: 0.5 * p.mass * p.speed**2, moving))
   
   
  # Step 3: reduce() — add all the kinetic energies
  # Step 3: reduce() — add them all up
  total_ke = reduce(lambda acc, ke: acc + ke, ke_list, 0.0)
  total_ke = reduce(lambda acc, ke: acc + ke, ke_list, 0.0)
  print("Total KE of fast particles:", round(total_ke, 2), "J")
  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.
This filter → map → reduce pattern shows up all the time in physics simulations.
Pick a group of objects, apply a formula to each one, then get one final number
out of it. That is basically what these three functions are built for.
 
----
----


'''Gravitational potential energy at different heights:'''
g = 9.8  # m/s^2
m = 2.0  # kg
heights = [1.0, 5.0, 10.0, 20.0, 50.0]  # meters
pe_list = list(map(lambda h: m * g * h, heights))
# Result: [19.6, 98.0, 196.0, 392.0, 980.0]  Joules
'''Electric force on an electron at different distances from a charge (Coulomb's law):'''
k = 8.99e9  # N·m^2/C^2
Q = 1.0e-6  # source charge, Coulombs
r_list = [0.1, 0.2, 0.5, 1.0]  # meters
forces = list(map(lambda r: k * Q * 1.6e-19 / r**2, r_list))
----


== '''Interactive Simulation''' ==
== '''Interactive Simulation''' ==


The following GlowScript simulation demonstrates all three functions working  
The following GlowScript simulation shows all three functions working together
together in a physics context:
in a real physics example:
[https://trinket.io/glowscript/9e53d57b352f map(), filter(), and reduce() in VPython Physics — Trinket]
[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  
The simulation puts five spheres in a row, each with a different mass between
different mass (ranging from 1 to 8 kg) and a different speed (ranging from 1.5 to
1 and 8 kg and a different speed between 1.5 and 6 m/s. The size of each sphere  
6 m/s). The radius of each sphere is proportional to its mass.
matches its mass so you can see the difference right away.
 
The program then demonstrates each function in sequence:


* '''map()''' iterates over the list of masses and computes the gravitational weight  
* '''map()''' goes through every mass and calculates the weight using F = mg.  
of each sphere using Newton's second law (F = mg, with g = 9.8 m/s²). The results
The weight of each sphere gets printed to the console.
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  
* '''filter()''' checks each sphere's speed and keeps the ones faster  
3.0 m/s. Those spheres are turned '''red''' in the 3D scene, providing a visual
than 3.0 m/s.  
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  
* '''reduce()''' is written by hand since GlowScript does not have the  
not support the <code>functools</code> module. It adds the kinetic energy of every sphere into a single total. The individual kinetic energies
<code>functools</code> module. It adds up the kinetic energy of every sphere  
and the system total are printed to the console.
one by one until it has one total number for the whole system, which then
gets printed.


Together, the simulation illustrates the filter → map → reduce pipeline in a
This simulation is an accurate visualization of how all three functions work together.
physical setting, showing how the three functions complement each other.


----
----

Revision as of 20:24, 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. A typical VPython simulation can have hundreds of objects that all follow the same physics equations, and writing for-loops to do the same calculation over and over can be inefficient. map(), filter(), and reduce() take care of the for-loops, allowing you to focus on the point of the code itself.

Each function does something different:

  • map(): applies a function to every element in a list
  • filter(): iterates through a list and only keeps the elements that meet a certain condition
  • reduce(): takes a whole list and turns it into one single value

Python 3 note: map() and filter() do not actually work until you ask for the results. Wrap them in list() to get a list back. reduce() has to be imported before you can use it:

from functools import reduce

GlowScript note: GlowScript does not support lambda expressions or the functools module. Use regular def functions instead of lambdas, and write reduce() yourself. Here is an example of this in the simulation section below.


Background

In Python, functions are objects just like numbers or strings. That means you can:

  • Store a function in a variable
  • Pass a function into another function as an argument
  • Get a function back as a return value

This is what makes map(), filter(), and reduce() work. When you write map(calc_weight, masses), you are passing the function calc_weight itself into map(). Then map() runs it on every item in the list so you don't have to.

There are a few reasons why writing code this way is efficient:

  • It is easy to read: You can look at the code and immediately tell what it

is doing — like if you see "apply this formula to every mass" you just get it, no decoding required

  • Fewer bugs: Every time you write a for-loop you have to manually keep track of index

variables, which is easy to make mistakes on. These functions handle the indices, so there is less room for errors.

  • You can chain them: The output of map() can go straight into

filter() or reduce() without extra steps, which keeps the variables clean and short.


Lambda Expressions

A lambda expression is a function you write in one line without giving it a name. The format is:

lambda <parameters>: <expression>

The function only exists at the point where it is used. These two do the exact same thing:

# Regular way
def square(x):
    return x**2

# Lambda way
square = lambda x: x**2

Lambdas save you from having to define a whole separate function when you only need it once:

# Without lambda: needs a function defined somewhere else
result = list(map(square, [1, 2, 3, 4]))

# With lambda: no separate function needed
result = list(map(lambda x: x**2, [1, 2, 3, 4]))
# Result: [1, 4, 9, 16]

They can also take two inputs, which comes up when using reduce():

from functools import reduce
total = reduce(lambda acc, x: acc + x, [1, 2, 3, 4], 0)
# Result: 10

Lambda vs def — when to use which:

  • Use a lambda when the function is short, only needed once, and passed right

into another function

  • Use def when the function is longer or used in multiple places

GlowScript note: Lambdas do not work in GlowScript at all. Always use def when writing code for Trinket.


Inputs and Type Matching

All three functions follow the same basic structure:

function_name(function, list)

The first argument is the function you want to use. The second is the list of data you want to run it on, which can be a list, tuple, etc.

One thing to watch out for: the function has to be able to work with any item is in the list. If your list has decimal numbers but your function expects whole numbers, Python will throw an error.

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 thing with 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 straight in:

words = ['hello', 'world', 'vpython']
lengths = list(map(len, words))
# Result: [5, 5, 7]

Map()

How it works

map(function, list) runs a function on every single element in a list and gives you back all the results. The original list stays the same; you get a new list of updated values.

map(function, list)

So for a list [a, b, c, d] and some 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]

Physics examples

Gravitational weight (F = mg) for the 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

Kinetic energy of the 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 temperature 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

map() vs a for-loop

Both of these give the same answer, but map() is more concise:

# For-loop
weights = []
for m in masses:
    weights.append(m * 9.8)

# map() — same thing in one line
weights = list(map(lambda m: m * 9.8, masses))

Filter()

How it works

filter(function, list) iterates through a list and only keeps the elements where the function returns True.

filter(function, list)
filter(lambda x: condition, list)

Example

numbers = [3, 7, 5, 2, 1, 6]
result = list(filter(lambda x: x > 3, numbers))
# Result: [7, 5, 6]

Physics examples

Retrieving only the fastest particles:

speeds = [120, 340, 95, 500, 210, 80]  # m/s

fast_particles = list(filter(lambda v: v > 200, speeds))
# Result: [340, 500, 210]

Keeping the positive charges:

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]

Removing particles that exited the simulation boundary:

# Each particle p has a .pos.x value for its x position
boundary = 10.0  # meters

inside = list(filter(lambda p: abs(p.pos.x) < boundary, particles))

Passing None as the function

If you pass None instead of a function, filter() removes every zero, empty string, None, and False from the list:

messy = [1, 0, 3, None, 5, 0, 7]
clean = list(filter(None, messy))
# Result: [1, 3, 5, 7]

Reduce()

How it works

reduce(function, list, starting value) takes a whole list and returns one single value. Unlike map() and filter(), you do not get a list back — you get one number.

The function you pass in needs to take two inputs:

  • The running total so far
  • The next item in the list

After each step, the result becomes the new total for the next step.

from functools import reduce
reduce(function, list, starting value)

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 up all the 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 fastest particle in a list:

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

Total work done (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

Watch out

Always give reduce() a starting value as the third argument. If the list is empty and there is no starting value, Python will crash. With a starting value, an empty list will give you that value back instead:

reduce(lambda acc, x: acc + x, [], 0.0)
# Returns 0.0 safely

Combining map(), filter(), and reduce()

It is also efficient that functions can be chained together.

Example: kinetic energy

from functools import reduce

# Step 1: filter() — drop all values below 3.0 m/s
moving = list(filter(lambda p: p.speed > 3.0, particles))

# Step 2: map() — calculate KE for each remaining particle
ke_list = list(map(lambda p: 0.5 * p.mass * p.speed**2, moving))

# Step 3: reduce() — add them all up
total_ke = reduce(lambda acc, ke: acc + ke, ke_list, 0.0)
print("Total KE of fast particles:", round(total_ke, 2), "J")

This filter → map → reduce pattern shows up all the time in physics simulations. Pick a group of objects, apply a formula to each one, then get one final number out of it. That is basically what these three functions are built for.


Gravitational potential energy at different heights:

g = 9.8   # m/s^2
m = 2.0   # kg
heights = [1.0, 5.0, 10.0, 20.0, 50.0]  # meters

pe_list = list(map(lambda h: m * g * h, heights))
# Result: [19.6, 98.0, 196.0, 392.0, 980.0]  Joules

Electric force on an electron at different distances from a charge (Coulomb's law):

k = 8.99e9   # N·m^2/C^2
Q = 1.0e-6   # source charge, Coulombs
r_list = [0.1, 0.2, 0.5, 1.0]  # meters

forces = list(map(lambda r: k * Q * 1.6e-19 / r**2, r_list))

Interactive Simulation

The following GlowScript simulation shows all three functions working together in a real physics example: map(), filter(), and reduce() in VPython Physics — Trinket

The simulation puts five spheres in a row, each with a different mass between 1 and 8 kg and a different speed between 1.5 and 6 m/s. The size of each sphere matches its mass so you can see the difference right away.

  • map() goes through every mass and calculates the weight using F = mg.

The weight of each sphere gets printed to the console.

  • filter() checks each sphere's speed and keeps the ones faster

than 3.0 m/s.

  • reduce() is written by hand since GlowScript does not have the

functools module. It adds up the kinetic energy of every sphere one by one until it has one total number for the whole system, which then gets printed.

This simulation is an accurate visualization of how all three functions work together.


References

1. Python map, filter, reduce — bogotobogo.com

2. Map, Filter — Python Tips

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

13. GlowScript VPython — Official Site

14. GlowScript on Trinket

15. VPython Official Documentation