In this tutorial, you’ll learn how to use Python to flatten lists of lists! You’ll learn how to do this in a number of different ways, including with for-loops, list comprehensions, the itertools
library, and how to flatten multi-level lists of lists using, wait for it, recursion! Let’s take a look at what you’ll learn in this tutorial!
The Quick Answer: Use a Python List Comprehension to Flatten Lists of Lists
Table of Contents
What is a Python List of Lists?
In Python, a list of a lists is simply a list that contains other lists. In fact, lists of lists in Python can even contain other lists of lists! We can say that a list that contains only one other layer of lists is called a 2-dimensional list of lists. When one or more of these lists contain another list, we say they’re called 3-dimensional. This continues onwards, as we add more and more layers.
When you convert a list of lists, or a 2-dimensional array, into a one-dimensional array, you are flattening a list of lists. Learn four different ways to do this in this tutorial!
Let’s take a look at a simple list of lists in Python, so that you can have a visual depiction of what they actually look like:
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
When we try to access the third item, index position 2
, we can print out what it contains:
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(list_of_lists[2])
# Returns: [4, 5, 6]
We can see here that the third item of our list list_of_lists
is actually another list. This is what we mean by lists of lists – they are lists that contain other lists.
In the next section, you’ll learn how to use a naive method, a for-loop, to flatten a list of lists.
How to Use a Python For Loop to Flatten Lists of Lists?
Now that you know what a Python list of lists is, let’s see how we can use a Python for-loop to flatten them!
In our for-loop, we’ll loop over each item in the list and add each item to a new list.
Let’s see how we can accomplish this with Python:
# Use a for-loop to flatten a list of lists
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat_list = list()
for sub_list in list_of_lists:
flat_list += sub_list
print(flat_list)
# Returns: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Let’s break down what we’ve done here step-by-step:
- We loaded our
list_of_lists
- We generated a new list, called
flat_list
- We looped over each item, or list, in the list of lists and added each item’s values to our
flat_list
Now that you’ve used a for-loop to flatten a list of lists, let’s learn how you can use list comprehensions to flatten them!
Want to learn more? Check out my in-depth tutorial on Python for-loops here!
How to Use a List Comprehension in Python to Flatten Lists of Lists?
Python list comprehensions are elegant, Pythonic replacements for Python for-loops. In fact, any list comprehension can actually be expressed as a for-loop (though the reverse isn’t necessarily true).
So why write a list comprehension when a for-loop might do? There are a number of benefits to using list comprehensions – let’s take a quick look at them here:
- You don’t need to instantiate a new empty list
- You can write it over one line, rather than needing to split it out over multiple lines
- They’re more Pythonic than for-loops
Want to learn more? Check out my in-depth tutorial on Python list comprehensions here!
Let’s take a look at how Python list comprehension look:
Now, let’s see how we can use list comprehensions to flatten Python lists of lists:
# Use a List Comprehension to Flatten a List of Lists
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat_list = [item for sublist in list_of_lists for item in sublist]
print(flat_list)
# Returns: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Keep in mind that this does exactly what the for-loop is doing. The syntax can take a bit of getting used to, but once you master it, it becomes second nature and saves you a good amount of time!
How to Use Itertools to Flatten Python Lists of Lists
Both of the methods we’ve covered off so far don’t require you to import a different library. Now, let’s take a look at how we can use the itertools
library to flatten Python lists of lists.
In particular, we’ll use the chain
function to to loop over each individual item in the larger list and add it to the larger list. Finally, since the chain
function would return an itertools.chain
object, we need to convert it back to a list.
Let’ see how we can do this here:
from itertools import chain
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat_list = list(chain(*list_of_lists))
print(flat_list)
# Returns: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Since we rely on variable unpacking, it’s not immediately clear what’s happening in the code (as some other custom functions might). Because of this, make sure you document your code well!
Check out some other Python tutorials on datagy.io, including our complete guide to styling Pandas and our comprehensive overview of Pivot Tables in Pandas!
How to Flatten Multi-level Lists of Lists in Python?
Now, there may be times that you encounter more complex lists, such as the one shown below. Using one of these methods shown above won’t work, as they require you to have similar levels within their lists.
list_of_lists = [1, [2, 3], [4, [5, 6]], [7, 8], 9]
We can see that in our lists, we have some items at the root level, and some lists embedded in other lists.
In order to flatten this list of lists, we will need to think a bit more creatively. In particular, we can develop a function that calls itself recursively to unpack lists of lists.
Let’s see how we can do this in Python (thanks for the fix, Chengju!):
# Flatten a multi-level list of lists with recursion
list_of_lists = [1, [2, 3], [4, [5, 6]], [7, 8], 9]
def flatten_list(list_of_lists, flat_list=None):
if not flat_list:
flat_list = []
if not list_of_lists:
return flat_list
else:
for item in list_of_lists:
if type(item) == list:
flatten_list(item, flat_list)
else:
flat_list.append(item)
return flat_list
flat_list = flatten_list(list_of_lists)
print(flat_list)
# Returns: [1, 2, 3, 4, 5, 6, 7, 8, 9]
This example is a bit more complex, so let’s see what we’ve done here:
- We generate a new function
flatten_list
that takes a list of lists as an input as well as an empty list by default - We evaluate is our
flat_list
is still an empty list. If it is, we return itself. Otherwise, we loop over each item and process the steps below. - We then loop over each item in the list
- We check if the type of the item is a list:
- If it is a list, then we call the function again
- If it isn’t, we append the item to our
flat_list
We can see here that this works quite simply and is actually adaptable to any number of nesting!
Conclusion
In this post, you learned how to use Python to flatten lists of lists. You also learned what lists of lists in Python actually are. In addition to this, you learned how to use for-loops and list comprehensions to flatten lists of lists in Python. You also learned how to use the itertools
library to flatten lists of lists. Finally, you learned how to use recursion to multi-level lists of lists.
To learn more about the itertools
library, check out the official documentation here.
Additional Resources
To learn more about related topics, check out the tutorials below:
Your flatten_list doesn’t save the result of flatten_list(item). You need to extend flat_list with that result as shown below. You also need to set flat_list to empty list inside the flatten_list function so it starts out as an empty list with every invocation of flatten_list.
def flatten_list(list_of_lists):
flat_list = []
for item in list_of_lists:
if type(item) == list:
flat_list.extend(flatten_list(item))
else:
flat_list.append(item)
return flat_list
Hi Walter, thanks for your comment and for the note! Since the function works recursively to check if the item is a list first, we don’t need to use the extend method. This prevents accidentally appending a nested list of lists.
I do agree about including the flattened list outside of the function is not a great way of handling this. I have modified the code :).
Thanks for your thoughtful comment! 🙂
Given the beginner level of the topic (which is great) you really should break down the += operator in your “breaking it down” section because that is specialized overloaded operator for lists: namely “add” means “combine” two lists and += means combine and re-assign.
Thanks for the feedback!
Consider explaining list comprehension rather than just pasting code. There is no way somebody who isn’t familiar with list-of-lists will know what’s going on with that. Breaking it down:
for sublist in list_of_lists
for item in sublist.
append(item)
Finally, the magical “[item” term appends the value of item to the new list. That last part is not obvious and the source of confusion. You can see it reads cleanly as nested for loops from left (outer) to right (inner) until you get to that append part.
Thanks for the feedback, Rick! I’m looking to update this post soon so the feedback really helps.
Thanks for the nice posts. I found some issues with the method of flatten_list.
(1) The 2nd argument should not be default. A single call is fine but a consecutive call will result in unwanted results.
Try
list_number = [1, [2, 3], [4, [5, 6]], [7, 8], 9]
list_letter = [‘A’, [‘B’, ‘C’], [‘D’, [‘E’]], [‘F’, ‘G’], ‘H’]
==>
Expected
flatten_list(list_number) = [1, 2, 3, 4, 5, 6, 7, 8, 9]
flatten_list(list_letter) = [‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’]
But I got the following
flatten_list(list_number) = [1, 2, 3, 4, 5, 6, 7, 8, 9]
flatten_list(list_letter) = [1, 2, 3, 4, 5, 6, 7, 8, 9, ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’]
The correct call is flatten_list(list_number, []) & flatten_list(list_letter, [])
(2) The terminate condition for the recursive should be the following
if not list_of_lists:
return flat_list
(3) The cursive call inside the method should be input with the 2nd argument
if type(item) == list:
flatten_list(item, flat_list)
The update version is
def flatten_list(list_of_lists, flat_list=[]):
if not list_of_lists:
return flat_list
else:
for item in list_of_lists:
if type(item) == list:
flatten_list(item, flat_list)
else:
flat_list.append(item)
return flat_list
Thank you so much, Chengju! I have updated the code. I really appreciate you taking the time to leave a comment with the fix!
def flatten_list(list_of_lists, flat_list=None):
if not flat_list:
flat_list = []
if not list_of_lists:
return flat_list
else:
for item in list_of_lists:
if type(item) == list:
flatten_list(item, flat_list)
else:
flat_list.append(item)
return flat_list
———————————————————————————-
I’m surprised your code works.
How does the line 8 work?
Shouldn’t it be flat_list = flatten_list(item, flat_list)
I don’t get how it works in both ways.
Hi Muhan,
Since we’re using recursion, it suffices to not have it be assigned.
Hope that helps!
Can you explain the difference between using a for-loop and a list comprehension to flatten lists of lists in Python, and when would you choose one approach over the other?
In many ways, they operate similarly. List comprehensions can make your code more concise, but sometimes also harder to follow. I would say, use the approach that you’re most likely to understand two weeks from now :).
Hi,
cool article, but there is a subtle bug in one of the examples. You shouldn’t use mutable objects as default arguments. It will work as intended on the first run, but the subsequent calls of the function will use the modified object, yielding incorrect results. It is better to use `None`:
“`python
def flatten_list(list_of_lists, flat_list=None):
if flat_list is None:
flat_list = []
# rest of the code as before
…
“`
Thanks so much, Marek! That’s a really great point. I have updated the article :).