Chapter 5
def numbers_from_rows(conversion, text):
return (conversion(v) for line in text.splitlines() for v in
line.split())
This function has a conversion argument, which is a function that is applied to each
value that will be emitted. The values are created by flattening using the algorithm
shown above.
We can use this numbers_from_rows() function in the following kind of expression:
print(list(numbers_from_rows(float, text)))
Here we've used the built-in float() to create a list of floating-point values from
the block of text.
We have many alternatives using mixtures of higher-order functions and generator
expressions. For example, we might express this as follows:
map(float, v for line in text.splitlines() for v in line.split())
This might be helpful if it helps us understand the overall structure of the algorithm.
The principle is called chunking; the details of a function with a meaningful name
can be abstracted and we can work with the function in a new context. While we
often use higher-order functions, there are times when a generator expression can be
more clear.
Structuring data while filtering
The previous three examples combined additional processing with mapping.
Combining processing with filtering doesn't seem to be quite as expressive as
combining with mapping. We'll look at an example in detail to show that, although
it is useful, it doesn't seem to have as compelling a use case as combining mapping
and processing.
In Chapter 4, Working with Collections, we looked at structuring algorithms.
We can easily combine a filter with the structuring algorithm into a single, complex
function. The following is a version of our preferred function to group the output from
an iterable:
def group_by_iter(n, iterable):
row= tuple(next(iterable) for i in range(n))
while row:
yield row
row= tuple(next(iterable) for i in range(n))