guys. I'm trying to find the most elegant solution to a problem and wondered if python has anything built-in for what I'm trying to do.
What I'm doing is this. I have a list, A
, and I have a function f
which takes an item and returns a list. I can use a list comprehension to convert everything in A
like so;
[f(a) for a in A]
But this return a list of lists;
[a1,a2,a3] => [[b11,b12],[b21,b22],[b31,b32]]
What I really want is to get the flattened list;
[b11,b12,b21,b22,b31,b32]
Now, other languages have it; it's traditionally called flatmap
in functional programming languages, and .Net calls it SelectMany
. Does python have anything similar? Is there a neat way to map a function over a list and flatten the result?
The actual problem I'm trying to solve is this; starting with a list of directories, find all the subdirectories. so;
import os dirs = ["c:\\usr", "c:\\temp"] subs = [os.listdir(d) for d in dirs] print subs
currentliy gives me a list-of-lists, but I really want a list.
As we can see, the for loop is slower than the list comprehension (9.9 seconds vs. 8.2 seconds). List comprehensions are faster than for loops to create lists. But, this is because we are creating a list by appending new elements to it at each iteration.
As it turns out, you can nest list comprehensions within another list comprehension to further reduce your code and make it easier to read still. As a matter of fact, there's no limit to the number of comprehensions you can nest within each other, which makes it possible to write very complex code in a single line.
List comprehensions are used for creating new lists from other iterables. As list comprehensions return lists, they consist of brackets containing the expression, which is executed for each element along with the for loop to iterate over each element.
You can have nested iterations in a single list comprehension:
[filename for path in dirs for filename in os.listdir(path)]
which is equivalent (at least functionally) to:
filenames = [] for path in dirs: for filename in os.listdir(path): filenames.append(filename)
>>> from functools import reduce >>> listOfLists = [[1, 2],[3, 4, 5], [6]] >>> reduce(list.__add__, listOfLists) [1, 2, 3, 4, 5, 6]
I'm guessing the itertools solution is more efficient than this, but this feel very pythonic.
In Python 2 it avoids having to import a library just for the sake of a single list operation (since reduce
is a built-in).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With