How to flatten a Python List or array and which one should you use and when
By: Leonidas Constantinou
Tags: Complexity, Benchmark, Arrays, Numpy, Python

How to flatten a Python List or array and which one should you use and when Leonidas Constantinou 1 day ago·8 min read

This is a long post so you can skip to any section using the Table of Content below:

- 1. Python List

— | 1.1 List Comprehension

— | 1.2 sum()

— | 1.3 itertools.chain()

— | 1.4 functools & operator

- 2. Numpy Arrays

— |2.1 flat

— |2.2 flatten()

— |2.3 ravel()

— |2.4 reshape(-1)

— |2.5 concatenate()

— |2.6 Method comparison

- 3. Benchmark

— |3.1 Fastest method overall

— |3.2 Complexity over time while we increase the dimensions

- 4. Conclusion

Oftentimes, when you write code you will need to reduce a nested List or a Numpy array to 1D. In other words, you want to flatten your list. Luckily, there are many ways to do this in Python. But which one should you use? In this article, we will explore various methods to achieve this task and benchmark them in order to identify which one is the most optimal method.

1. Python Lists

Here is an example of a 2D List:

list_2D = [[1,2,3],[4],[5,6],[7,8,9]]

and we want to flatten it into:

list_1D = [1,2,3,4,5,6,7,8,9]

1.1 List Comprehension

This is the most Pythonic way. Even though nested list comprehension is not easy on the eye, it’s a really simple method. For those who understand list comprehensions, you can skip the explanation.

list_1D = [item for sub_list in list_2D for item in sub_list]

If we were to code this using nested loops we will write it like this:

list_1D = []

for sub_list in list_2D:

for item in sub_list:

list_1D.append(item)

In order to convert the above code into a single liner you should break it into 3 parts:

Image by author

Outer Loop

Inner Loop

output expression

You start a list comprehension by opening square brackets and re-write the above steps as follows:

Define the output expression Define the outer loop Define the inner loop

1.2 sum()

Even though this method was designed to sum numeric values, it works with concatenating lists as well. It’s a really simple solution but not an ideal one since it won’t perform as well when it comes to a larger list. Overall it’s an inefficient method but a quick hack. We will see the benchmark results at the end of this post. sum() is a built-in function that takes an iterable and sums the items from left to right.

Warning It is not advised to use this method in production

list_1D = sum(list_2D, [])

This method takes 2 arguments. It sums the items of the iterable which is passed as the first argument and it uses the second argument as the initial value of the sum. This is an optional argument though, but since we are trying to sum nested lists, we want to start the concatenation with an empty list. So the above function is equivalent to this:

list_1D = [] + [1,2,3] + [4] + [5,6] + [7,8,9]

You can imagine what will happen if we had many more sublists. This is really inefficient and not ideal for production apps. A nice metaphor to describe this is the Shlemiel the painter’s algorithm written by Joel Spolsky.

In addition, if you want to check the complexity and the math of this method here is a nice read How Not to Flatten a List of Lists in Python

As it is stated on the official Python Docs there is an alternative method that is calleditertools.chain() .

1.3 itertools.chain()

Below you can find the code provided by the Python Official Documentation on how to use the chain() function.

def chain(*iterables):

# chain('ABC', 'DEF') --> A B C D E F

for it in iterables:

for element in it:

yield element

It takes as input multiple iterables and returns the elements of each iterable one by one until all iterables are exhausted.

from itertools import chain

# [1, 2, 3, 4]

list(chain([1,2], [3,4])

In our case, we only have one iterable which is a nested list. Luckily for us, there is another method designed for that which is called from_iterable() .

def from_iterable(iterables):

# chain.from_iterable(['ABC', 'DEF']) --> A B C D E F

for it in iterables:

for element in it:

yield element

And since this function returns a chain object, we make sure we use the list constructor in order to return the flatten iterable like a list.

from itertools import chain

list_1D = list(chain.from_iterable(list_2D))

import functools

import operator



functools.reduce(operator.iconcat, list_2D, [])

Functools is a library used mostly for higher-order functions, a term used in Functional Programming. Using the reduce function, we want to pass a function as the first argument in order to reduce the iterable (passed as the second argument) to a single value. The third argument is the initialiser and this is optional.

The function to be used is the iconcat operator which basically translates to : a += b

print(operator.iconcat([1,2],[3,4]))

# [1, 2, 3, 4]

So, in the end, this is equivalent to :

list_1D = [] + [1,2,3] + [4] + [5,6] + [7,8,9]

This is the same result as the one on method in section 1.2 however, this is much more efficient