Previously we discussed topics like iterators, list comprehensions, and generator expressions. If you feel like you need a refresher on that matter, you can find it by following the link. πππ
Today, we are going to take a look at lambdas, map, and filter functions, powerful yet elegant tools. They are often used in functional programming to perform operations on data without the need for explicit loops.
Lambda functions
Sometimes referred to as "anonymous functions", lambda functions or simply lambdas are a way to create small, inline functions without assigning them a name. They are useful when we need a simple function for a short duration or for specific operations where a full function definition seems unnecessary. For a refresher on the basics of functions in Python follow the link below. πππ
Lambda functions are defined using the lambda
keyword, followed by a list of arguments, a colon, and an expression. The result of the lambda function is the value of the expression. The basic syntax of the lambda function looks as follows.
lambda arguments: expression
A common use of lambda functions is for simple arithmetic operations. Here's a lambda function that calculates the square of a number.
>>> square = lambda x: x**2
>>> square(5)
25
In this example, the lambda function lambda x: x**2
takes one argument x
and returns the square of x
. As simple as that! A common use case of lambdas is using them along with map or filter functions.
Map
The map
function is a built-in function used for applying a given function to each item in an iterable (e.g., a list or tuple). It returns a new iterable with the results of applying the function to each element. Map is a powerful tool for data transformation, as it allows us to process data in an efficient way without the need for explicit loops. The map
function is used as follows.
map(function, iterable, ...)
The function
is what we want to apply to each element of the iterable. It can be a regular function or a lambda function. The iterable
is the sequence (e.g., a list or tuple) that we want to process using the given function.
We can use the map
function for simple mapping operations. Let's start with a basic example. Suppose we have a list of numbers, and we want to square each number using a lambda function and map
.
>>> numbers = [1, 2, 3, 4, 5]
>>> squared = map(lambda x: x**2, numbers)
>>> squared_list = list(squared)
>>> print(squared_list)
[1, 4, 9, 16, 25]
The lambda function lambda x: x**2
is applied to each element in the numbers
list, creating a new iterable squared
with the squared values.
We can use map
to convert elements from one data type to another. For instance, we can convert a list of integers to a list of strings.
>>> numbers = [1, 2, 3, 4, 5]
>>> string_numbers = map(lambda x: str(x), numbers)
>>> string_numbers_list = list(string_numbers)
>>> print(string_numbers_list)
['1', '2', '3', '4', '5']
The lambda function lambda x: str(x)
is applied to each element in the numbers
list, creating a new iterable string_numbers
with the string values.
We can map multiple iterables by providing more than one iterable as arguments. The function should accept the same number of arguments as there are iterables. For example, we can add corresponding elements from two lists.
>>> list1 = [1, 2, 3]
>>> list2 = [4, 5, 6]
>>> sum_result = map(lambda x, y: x + y, list1, list2)
>>> sum_list = list(sum_result)
>>> print(sum_list)
[5, 7, 9]
The code essentially adds the elements of list1
and list2
together, creating a new list sum_list
with the results [5, 7, 9]
.
Finally, instead of using a lambda function, we can use a custom function with map
. For instance, we can have a custom function that capitalizes the first letter of a string.
>>> def capitalize_first_letter(s):
... return s.capitalize()
>>> words = [f'apple', f'banana', f'cherry']
>>> capitalized_words = map(capitalize_first_letter, words)
>>> capitalized_words_list = list(capitalized_words)
>>> print(capitalized_words_list)
['Apple', 'Banana', 'Cherry']
The above code effectively capitalizes the first letter of each word in the words
list using capitalize_first_letter
function and stores the modified words in capitalized_words_list
.
Let's recall our Car
class from previous posts.
class Car:
def __init__(self, make: str, model: str):
self.make: str = make
self.model: str = model
def __str__(self) -> str:
return f'{self.make} {self.model}'
def __repr__(self) -> str:
return f'{self.make} {self.model}'
We have added the __repr__
method for correct printing into the console output. Now we can try to create a list of cars of a single brand using map
function.
>>> models = [f'Camry', f'Corolla', f'Prius', f'Camry', f'Corolla', f'Prius', f'Camry', f'Corolla', f'Prius']
>>> cars = map(lambda model: Car(f'Toyota', model), models)
>>> cars_list = list(cars)
>>> print(cars_list)
[Toyota Camry, Toyota Corolla, Toyota Prius, Toyota Camry, Toyota Corolla, Toyota Prius, Toyota Camry, Toyota Corolla, Toyota Prius]
The provided code initializes a list of car models containing Camry, Corolla, and Prius. It then uses the map
function with a lambda expression to create a list of Car
objects, each having Toyota as the make and one of the models from the initial list. The resulting cars
map object is converted to a list called cars_list
, which contains the Car
objects. When printed, the output displays a list of Car
objects, each representing a Toyota car with a different model.
Filter
Another helpful function is the filter
function. It is a built-in function used to filter elements from an iterable (e.g., a list or tuple) based on a specified function (usually a lambda function) that returns either True
or False
. It returns a new iterable containing only the elements for which the function evaluates to True
. The primary use case for the filter
function is to selectively extract and process data based on specific conditions.
In general, the filter
function syntax is as follows.
filter(function, iterable)
The function
takes an element from the iterable and returns either True
or False
to determine if the element should be included in the output. The iterable
is the sequence (e.g., a list or tuple) from which we want to filter elements.
Let's start with a basic example of a filtering operation using a lambda function. Suppose we have a list of numbers, and we want to filter out only the even numbers using a lambda function and filter
.
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> even_numbers = filter(lambda x: x % 2 == 0, numbers)
>>> even_numbers_list = list(even_numbers)
>>> print(even_numbers_list)
[2, 4, 6, 8, 10]
In the above example, the lambda function lambda x: x % 2 == 0
checks whether a number is even, and filter
creates a new iterable (even_numbers
) containing only the even numbers.
Previously, we have created the following list with cars.
[Toyota Camry, Toyota Corolla, Toyota Prius, Toyota Camry, Toyota Corolla, Toyota Prius, Toyota Camry, Toyota Corolla, Toyota Prius]
filter
function can be easily used to filter this list. For that purpose let's extend the Car
interface with an is_model
method. It will allow us to query for the model of a car so it looks as follows.
class Car:
def __init__(self, make: str, model: str):
self.make: str = make
self.model: str = model
def __str__(self) -> str:
return f'{self.make} {self.model}'
def __repr__(self) -> str:
return f'{self.make} {self.model}'
def is_model(self, model: str) -> bool:
return model in self.model
Now we can easily write a lambda function to filter all the Corollas.
>>> models = [f'Camry', f'Corolla', f'Prius', f'Camry', f'Corolla', f'Prius', f'Camry', f'Corolla', f'Prius']
>>> cars = map(lambda model: Car(f'Toyota', model), models)
>>> filtered_cars = filter(lambda car: car.is_model(f'Corolla'), cars)
>>> print(list(filtered_cars))
[Toyota Corolla, Toyota Corolla, Toyota Corolla]
The provided code first defines a list named models
containing repeated car model names. It then uses the map
function with a lambda expression to create a collection of Car
objects, each labeled as Toyota with one of the models from the models
list. Subsequently, the filter
function is applied to the cars
collection, selecting only the Car
objects matching the model Corolla through a defined is_model
method. Finally, the code prints a list of Toyota Corolla cars, which are instances of the Car
class.
Summary
Lambda functions, map
, and filter
are essential elements for functional programming and data manipulation. Lambda functions provide a succinct way to create simple functions without formal declarations. Map
simplifies applying a function to every element in an iterable, producing a new one with the results. Filter
allows for selective extraction of elements based on specified conditions. These features collectively streamline data processing, enhance code readability, and offer invaluable flexibility for Python developers.