When using a spreadsheet it can be as easy as using the
TRANSPOSE
function on a range to transform the rows and columns into columns and rows, but how do you do that in Python?
To transpose a list of lists in Python first flatten the two-dimensional list into a one-dimensional list then use the following:
[flat_list[e::len(list_2d[0])] for e in range(len(list_2d[0]))]
where
flat_list
represents the flattened list, and
list_2d
represents the original 2D list.
Example
Here’s a running example of how this works:
list_2d = [[2020, 2021, 2022], ["A", "B", "C"]]
# transpose this list so that instead of being a 3 x 2 dimension, it will be a 2 x 3, like so:
transposed_list = [[2020, "A"], [2021, "B"], [2022, "C"]]
The first step is to flatten the list of lists . Once the list of lists has been flattened you can then proceed to build the new transformed list.
Any of the examples used in the post on flattening a list of lists will be able to achieve the same outcome (just apply the method that best suits your use case), but for the sake of this example, I’m going to use the simple multiple for-loops in list comprehension example to flatten the original list.
Here’s how this looks so far using the working example:
list_2d = [[2020, 2021, 2022], ["A", "B", "C"]]
flat_list = [cell for row in list_2d for cell in row]
print(flat_list)
>> [2020, 2021, 2022, 'A', 'B', 'C']
Now that we’ve been able to achieve the flattening of our original 2D list, the next step is to map what the new dimension of each cell needs to be referenced to.
For example, in the new flattened list, each element in this list came from the original 2D list and the co-ordinates where each element came from the original are as follows:
flat_list => [2020, 2021, 2022, 'A', 'B', 'C']
orig_coord => [R1C1, R1C2, R1C3, R2C1, R2C2, R2C3]
To transform the flat list into a transposed list the coordinates of each element now need to be inserted into a new list of lists where the coordinates look something like this:
new_coord => [R1C1, R2C1, R1C2, R2C2, R1C3, R2C3]
To capture these values from the flattened list you would need the following index references:
idx_in_flat_list => [0, 3, 1, 4, 2, 5]
This pattern is important to see as it can help when slicing the list.
Transpose 2D List
As there is a nice linear pattern we can apply some simple means to create a new transposed list of lists, here’s one such method using a list comprehension .
# get length of row - the first row should be the same size as every other row
row_len = len(list_2d[0])
transposed_list = [flat_list[e::row_len] for e in range(row_len)]
print(transposed_list)
>> [[2020, 'A'], [2021, 'B'], [2022, 'C']]
As you can see from the above example the list comprehension and spread operator enables a 2D list to be transposed into the result being sought.
There are a couple of things going on in this statement which I’ll break apart, starting for the easiest to understand the
for-loop
.
What Does
For x In Range(y)
Do?
To loop through a series of numbers using Python combine the standard
for
statement with
the
range
function
. The
range
function has the following formats depending upon how many parameters you’re using:
range(stop)
range(start, stop, [step=1])
If using just one parameter, the assumption is a sequence starting at zero. Therefore, having
range(2)
would produce the sequence
0, 1
.
When entering 2 or more parameters into the
range
function, the first parameter is the starting value, the second parameter is the stop value (excluding itself) and the third parameter (if used) is the increment from start to stop.
Combining the
for
statement with the
range
function permits the use of iteration through the sequence produced by the
range
function. Therefore, this process is somewhat the same to other languages with their for-loops such as Javascript which has:
for( start = 0; start < stop; start += 1)
.
Finally, when using all of this in a set of square brackets on one line in Python you have created what is otherwise known as a list comprehension and in its simplicity produces the following results:
[e for e in range(3)]
>> [0, 1, 2]
[e for e in range(0, 3)]
>> [0, 1, 2]
[e for e in range(0, 3, 2)]
>> [0, 2]
For the purpose of being able to transpose a list of lists, the purpose of using this is to iterate through one dimension, and with the running example the rows are used as the range to loop through, which produces the following list of index numbers:
row_len = len(list_2d[0])
[e for e in range(row_len)]
>> [0, 1, 2]
This provides the seed for capturing the necessary data from the flattened list.
Slice Operator
The second part of the statement, which is the first part seen, involves the slice list operator:
list[start:stop:step]
very similar to the way the
range
function works the slice operator enables the use of obtaining values from a list according to the values used inside in the slice operation.
Here’s how this slice operation works with each iteration through from the
range
function:
e = 0
flat_list[0::3] => [2020, "A"]
e = 1
flat_list[1::3] => [2021, "B"]
e = 2
flat_list[2::3] => [2022, "C"]
As these are all wrapped into a list comprehension each result from the above slice operation is added as its own element in the new list.
Summary
To transpose a list of lists in Python use the following two steps: flatten your list of lists into a one-dimensional list, then use the following statement to transpose:
[flat_list[e::len(list_2d[0])] for e in range(len(list_2d[0]))]
You could wrap what you’ve learned above into a simple 2 line function if you wanted, perhaps something like so:
def transpose_2d_list(list_2d):
flat_list = [cell for row in list_2d for cell in row]
return [flat_list[e::len(list_2d[0])] for e in range(len(list_2d[0]))]
test = [[2020, 2021, 2022], ["A", "B", "C"]]
print(transpose_2d_list(test))
>> [[2020, 'A'], [2021, 'B'], [2022, 'C']]