5.14 Filter, Map and Reduce

The preceding section introduced several functional-style features—list comprehensions, filtering and mapping. Here we demonstrate the built-in filter and map functions for filtering and mapping, respectively. We continue discussing reductions in which you process a collection of elements into a single value, such as their count, total, product, average, minimum or maximum.

Filtering a Sequence’s Values with the Built-In filter Function

Let’s use built-in function filter to obtain the odd values in numbers:

In [1]: numbers = [10, 3, 7, 1, 9, 4, 2, 8, 5, 6]

In [2]: def is_odd(x):
   ...:     """Returns True only if x is odd."""
   ...:     return x % 2 != 0
   ...:

In [3]: list(filter(is_odd, numbers))
Out[3]: [3, 7, 1, 9, 5]

Like data, Python functions are objects that you can assign to variables, pass to other functions and return from functions. Functions that receive other functions as arguments are a functional-style capability called higher-order functions. For example, filter’s first argument must be a function that receives one argument and returns True if the value should be included in the result. The function is_odd returns True if its argument is odd. The filter function calls is_odd once for each value in its second argument’s iterable (numbers). Higher-order functions may also return a function as a result.

Function filter returns an iterator, so filter’s results are not produced until you iterate through them. This is another example of lazy evaluation. In snippet [3], function list iterates through the results and creates a list containing them. We can obtain the same results as above by using a list comprehension with an if clause:

In [4]: [item for item in numbers if is_odd(item)]
Out[4]: [3, 7, 1, 9, 5]

Using a lambda Rather than a Function

For simple functions like is_odd that return only a single expression’s value, you can use a lambda expression (or simply a lambda) to define the function inline where it’s needed—typically as it’s passed to another function:

In [5]: list(filter(lambda x: x % 2 != 0, numbers))
Out[5]: [3, 7, 1, 9, 5]

We pass filter’s return value (an iterator) to function list here to convert the results to a list and display them.

A lambda expression is an anonymous function—that is, a function without a name. In the filter call

filter(lambda x: x % 2 != 0, numbers)

the first argument is the lambda

lambda x: x % 2 != 0

A lambda begins with the lambda keyword followed by a comma-separated parameter list, a colon (:) and an expression. In this case, the parameter list has one parameter named x. A lambda implicitly returns its expression’s value. So any simple function of the form

def function_name(parameter_list):
    return expression

may be expressed as a more concise lambda of the form

lambda parameter_list: expression

Mapping a Sequence’s Values to New Values

Let’s use built-in function map with a lambda to square each value in numbers:

In [6]: numbers
Out[6]: [10, 3, 7, 1, 9, 4, 2, 8, 5, 6]

In [7]: list(map(lambda x: x ** 2, numbers))
Out[7]: [100, 9, 49, 1, 81, 16, 4, 64, 25, 36]

Function map’s first argument is a function that receives one value and returns a new value—in this case, a lambda that squares its argument. The second argument is an iterable of values to map. Function map uses lazy evaluation. So, we pass to the list function the iterator that map returns. This enables us to iterate through and create a list of the mapped values. Here’s an equivalent list comprehension:

In [8]: [item ** 2 for item in numbers]
Out[8]: [100, 9, 49, 1, 81, 16, 4, 64, 25, 36]

Combining filter and map

You can combine the preceding filter and map operations as follows:

In [9]: list(map(lambda x: x ** 2,
   ...:          filter(lambda x: x % 2 != 0, numbers)))
   ...:
Out[9]: [9, 49, 1, 81, 25]

There is a lot going on in snippet [9], so let’s take a closer look at it. First, filter returns an iterable representing only the odd values of numbers. Then map returns an iterable representing the squares of the filtered values. Finally, list uses map’s iterable to create the list. You might prefer the following list comprehension to the preceding snippet:

In [10]: [x ** 2 for x in numbers if x % 2 != 0]
Out[10]: [9, 49, 1, 81, 25]

For each value of x in numbers, the expression x ** 2 is performed only if the condition x % 2 != 0 is True.

Reduction: Totaling the Elements of a Sequence with sum

As you know reductions process a sequence’s elements into a single value. You’ve performed reductions with the built-in functions len, sum, min and max. You also can create custom reductions using the functools module’s reduce function. See https://docs.python.org/3/library/functools.html for a code example. When we investigate big data and Hadoop (introduced briefly in Chapter 1), we’ll demonstrate MapReduce programming, which is based on the filter, map and reduce operations in functional-style programming.

tick mark Self Check

  1. (Fill-In) _____, _____ and _____ are common operations used in functional-style programming.
    Answer: Filter, map, reduce.

  2. (Fill-In) A(n) _____ processes a sequence’s elements into a single value, such as their count, total or average.
    Answer: reduction.

  3. (IPython Session) Create a list called numbers containing 1 through 15, then perform the following tasks:

    1. Use the built-in function filter with a lambda to select only numbers’ even elements. Create a new list containing the result.

    2. Use the built-in function map with a lambda to square the values of numbers’ elements. Create a new list containing the result.

    3. Filter numbers’ even elements, then map them to their squares. Create a new list containing the result.

    Answer:

    In [1]: numbers = list(range(1, 16))
    
    In [2]: numbers
    Out[2]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
    
    In [3]: list(filter(lambda x: x % 2 == 0, numbers))
    Out[3]: [2, 4, 6, 8, 10, 12, 14]
    
    In [4]: list(map(lambda x: x ** 2, numbers))
    Out[4]: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225]
    
    In [5]: list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, numbers)))
    Out[5]: [4, 16, 36, 64, 100, 144, 196]
    
  4. (IPython Session) Map a list of the three Fahrenheit temperatures 41, 32 and 212 to a list of tuples containing the Fahrenheit temperatures and their Celsius equivalents. Convert Fahrenheit temperatures to Celsius with the following formula:

    Celsius = (Fahrenheit – 32) * (5 / 9)

    Answer:

    In [6]: fahrenheit = [41, 32, 212]
    
    In [7]: list(map(lambda x: (x, (x - 32) * 5 / 9), fahrenheit))
    Out[7]: [(41, 5.0), (32, 0.0), (212, 100.0)]
    

The lambda’s expression—(x, (x - 32) * 5 / 9)—uses parentheses to create a tuple containing the original Fahrenheit temperature (x) and the corresponding Celsius temperature, as calculated by (x - 32) * 5 / 9.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.171.20