0. Introduction

In this article, you’ll learn about Python’s lambda and higher-order functions like map, filter, and reduce, with clear explanations and runnable code examples.

1. Summary

Lambda Function:
A lambda function is a function without a name, also called an "anonymous function". It is useful for simple or one-time operations, especially when you want to write concise code.

Examples include sorting or filtering lists.

Higher-order Function:
A higher-order function is a function that either takes other functions as arguments or returns a function as a result.

Examples include filter, map and reduce.

2. Lambda Function

2.1. What is a lambda function?

A lambda function is called an "anonymous function", created on the fly as a function literal without defining it in advance like normal functions. Unlike normal functions, lambda functions are created on the fly and their names aren't fixed. It is therefore more flexible and can be used without a permanent name. For example, when sorting arrays (lists), the sorting criteria can be defined using a lambda function, which allows for flexible sorting.

2.2. Code (lambda functions)

print("\n---- List Sorting ----\n")

""" 
By using lambda expressions for sorting lists,
you can sort them flexibly.
"""

nums = [56, 91, 100, 68, 44, 21, 20, 36, 95, 15]

sorted_by_ascending = sorted(nums)  # sorted defaults to ascending order
sorted_by_descending = sorted(nums, key=lambda x: -x)  # To sort in descending order, negate the value in key
sorted_by_original = sorted(nums, key=lambda x: nums.index(x))  # To restore original order, sort by index (not necessary, but possible)
sorted_by_ones = sorted(nums, key=lambda x: x % 10)  # To sort by ones digit, use % 10

print("Ascending:", sorted_by_ascending)
print("Descending:", sorted_by_descending)
print("Original Order:", sorted_by_original)
print("Sorted by ones digit:", sorted_by_ones)
print("Original List:", nums)  # The original list remains unchanged

print("\n---- Tuple Sorting ----\n")

""" 
Tuples can also be flexibly sorted using lambda expressions,
just like lists. You can perform complex sorting like ascending by the first element (A), 
and descending by the second element (B).
"""

tuples = [(1, 2), (22, 31), (22, 11), (3, 5), (3, 1), (2, 41), (2, 13), (1, 1)]

sorted_by_first = sorted(tuples, key=lambda x: x[0])  # Ascending by the first element (A)
sorted_by_first_then_second_desc = sorted(tuples, key=lambda x: (x[0], -x[1]))  # Ascending by A, then descending by B

print("Sorted by first element (ascending):", sorted_by_first)
print("Sorted by first asc and second desc:", sorted_by_first_then_second_desc)

2.3. Execution Results

---- List Sorting ----

Ascending: [15, 20, 21, 36, 44, 56, 68, 91, 95, 100]
Descending: [100, 95, 91, 68, 56, 44, 36, 21, 20, 15]
Original Order: [56, 91, 100, 68, 44, 21, 20, 36, 95, 15]
Sorted by ones digit: [100, 20, 91, 21, 44, 95, 15, 56, 36, 68]
Original List: [56, 91, 100, 68, 44, 21, 20, 36, 95, 15]

---- Tuple Sorting ----

Sorted by first element (ascending): [(1, 2), (1, 1), (2, 41), (2, 13), (3, 5), (3, 1), (22, 31), (22, 11)]
Sorted by first asc and second desc: [(1, 2), (1, 1), (2, 41), (2, 13), (3, 5), (3, 1), (22, 31), (22, 11)]

3. Higher-Order Function

3.1. What is a Higher-Order Function?

A higher-order function is a function that either takes functions as arguments or returns them as a result.

3.1.1 Code (Higher-Order Function: Taking function as inputs)

""" 
A higher-order function is a function that takes other functions as arguments 
or returns them as a result.
"""

def higher_order_function(func):
    """
    Example of a higher-order function → takes a function as an argument
    """

    print("---- Start of process ----")
    func()  # Execute the function passed as an argument
    print("---- End of process ----")

def say_hello():
    """
    Example of a function to be passed as an argument
    """
    print("Hello, World!")

higher_order_function(say_hello)  # Pass say_hello as an argument

3.1.2. Execution Results (Higher-Order Function: Taking functions as inputs)

---- Start of process ----
Hello, World!
---- End of process ----

In the code in 3.1.1., the higher_order_function takes a function as arguments and execute processes.

3.1.3. Code (Higher-Order Function: Returning functions as outputs.)

""" 
A higher-order function is a function that takes other functions as arguments 
or returns them as a result.
"""

def higher_order_function():
    """
    Example of a higher-order function → returns a function
    """

    def inner_function():
        print("---- Executing inner function ----")

    return inner_function()

print("---- Start of process ----")
higher_order_function()  # Returns a function
print("---- End of process ----")

3.1.4. Execution Result (Higher-Order Function: Returning functions as outputs)

---- Start of process ----
---- Executing inner function ----
---- End of process ----

In the code in 3.1.3., the higher_order_function returns the inner_function as a result.

Higher-order functions can be used to separate processing responsibilities and combine several functions, which permits code abstraction and improved code reusability. In many languages, higher-order functions like map, filter or reduce are provided in advance and you can use them as a higher-order function.

3.2. Map Function (Higher-Order Function)

The map function is a function that can apply functions to a list or every elements in an array, return modified values as a new list or array.

3.2.1. Code (Higher-Order Function: Map Function)

""" 
map function: applies a function to each element
"""

def triple(x):
    return x * 3

nums = [1, 2, 3, 4, 5]

# Use the map function to apply the triple function to each element in the list
# The syntax is map(function, iterable)
# map returns an iterator, so we convert it to a list using list()
result = map(triple, nums)
print(f"Before applying triple: {nums}")  # [1, 2, 3, 4, 5]
print(f"After applying triple: {list(result)}")  # [3, 6, 9, 12, 15]
print(f"After applying triple - as iterable: {result}")

3.2.2. Execution Result (Higher-Order Function: Map Function)

Before applying triple: [1, 2, 3, 4, 5]
After applying triple: [3, 6, 9, 12, 15]
After applying triple - as iterable:

3.3. Filter Function (Higher-Order Function)

The filter Function is a function that takes a predicate function or list and execute it to each elements in the list to filter.

As an example, consider retrieving only the odd numbers of the numbers stored in the list.

3.3.1. Code (Higher-Order Function: Filter Function)

""" 
filter function: applies a function to each element in an iterable, 
and extracts only the elements for which the function returns True
"""

def is_odd(n):
    """Function to check whether a number is odd"""
    return n % 2 == 1

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Use the filter function to extract only odd numbers from nums
odd_nums = filter(is_odd, nums)

# odd_nums is an iterator, so convert it to a list before printing
# If you print odd_nums directly, you'll just see the filter object
print(f"List of odd numbers: {list(odd_nums)}")  # [1, 3, 5, 7, 9]
print(f"List of odd numbers - as iterator: {odd_nums}")

3.3.2. Execution Result (Higher-Order Function: Filter Function)

List of odd numbers: [1, 3, 5, 7, 9]
List of odd numbers - as iterator:

3.4. Reduce Function (Higher-Order Function)

The reduce function is a function for collapsing a sequence, such as a list, into a single value.

For examples, you can use it when you want to find the sum of a list or a product.

Reduce function takes 3 arguments:

  1. A function that takes two values and returns a result.
  2. A sequence to be processed. (e.g. a list)
  3. Any initial value

3.4.1. Code (Higher-Order Function: Reduce Function)

""" 
reduce function: applies a function to elements in an iterable,
accumulating the result into a single value.
"""

from functools import reduce

nums = [1, 2, 3, 4]

result = reduce(lambda x, y : x + y, nums, 0)
# Execution steps:
# step1: 0 + 1 = 1
# step2: 1 + 2 = 3
# step3: 3 + 3 = 6
# step4: 6 + 4 = 10

print(result) # 10

result_started_by_100 = reduce(lambda x, y : x + y, nums, 100)
# Execution steps:
# step1: 100 + 1 = 101
# step2: 101 + 2 = 103
# step3: 103 + 3 = 106
# step4: 106 + 4 = 110

print(result_started_by_100) # 110

3.4.2. Execution Result (Higher-Order Function: Reduce Function)

10
110