How to Find the Shape of a Nested List or Tuple in Python

Finding the shape of a nested list or tuple is much more complicated than finding the shape of a single element because each element in a list of lists or tuple of tuples can have a different dimension. Unlike NumPy arrays, lists and tuples aren’t required to have a set number of rows or columns.

To find the shape (or dimensions) of a nested list or tuple in Python, iterate over each element in the list or tuple and identify its length with the built-in len() function. This can become very complicated if the list or tuple has more than two dimensions. An example of how to identify the number of dimensions in a Python list or tuple, and the maximum size of each dimension is included below.

Create an Example List

Let’s start by creating a messy example list to work with. This list will have elements that contain integers, lists, and lists of lists. If this were a NumPy array it would be a 3-dimensional array. In other words (maybe more complicated words), the list contains a list, which contains another list.

list1 = [[1, 2, 3], [1, 2], [[2, 3, 4], [1, 3], 1], 9, [1, 2, 3]]

Keep Track of Dimensions

The trick with a list is that there’s no way to tell how many dimensions the list has without iterating through all the elements. That’s what we’re going to do here. As we iterate through the list we want to keep track of how many dimensions there are and the maximum size, or length, of each dimension. Let’s create a dims variable, and empty list, to keep track of the maximum length of each dimension. At then end of our script the length of dims will tell us the number of dimensions and the values in dims will tell us the maximum size of each dimension. It will be similar to a NumPy shape tuple, but for lists and tuples.

dims = []

Now we need a way to update dims when a new dimension is found, or a new maximum value for the length of an existing dimension is observed. To do this we’ll write a function that takes dims as an input, alters it (or not) according to other arguments, and then returns the updated dimension list.

The input arguments will be dims, the index to update or add, and the value to update or add. We want to add a dimension if we observe a list within a list and we want to update a value in dims if the length of a nested array is greater than the length of another nested array in the same dimension. I’m sure that’s a little confusing. Look at the code below to see how the function works. Then as we apply it in the next section it should start to make some more sense.

def set_dimension(dims, index, value):
    if len(dims) > index:
        if dims[index] < value:
            dims[index] = value
    else:
        dims.append(value)
    return dims

Find the Dimensions of a Nested List or Tuple

The first step is to set the first dimension of our list (list1). This is the easy part. The size of the first dimension is simply the number of elements in list1. For consistency, use set_dimensions to perform the update with the index argument set to 0.

set_dimension(dims, 0, len(list1))

To check your work print dims. Your output should match the output below.

Output:
[5]

There are 5 elements in list1. However, we cannot know what those elements are without iterating through each one. That’s what we’ll do now. Iterate through all the list elements with a nested loop. Within each loop check to see if an element is a list. If it is, use set_dimension to add a new dimension if it hasn’t been updated already or to update the size of the dimension. As stated, the example list only contains three dimensions. I’ve added a print statement in the third loop to indicate if a fourth dimension exists in the list so you can extend the functionality for other applications.

for i in range(len(list1)):
    if isinstance(list1[i], list):
        dims = set_dimension(dims, 1, len(list1[i]))
        for j in range(len(list1[i])):
            if isinstance(list1[i][j], list):
                dims = set_dimension(dims, 2, len(list1[i][j]))
                for k in range(len(list1[i][j])):
                    if isinstance(list1[i][j][k], list):
                        dims = set_dimension(dims, 3, len(list1[i][j][k]))
                        print('four dimensions')

The number of dimensions will be represented by the length of dims and maximum size of each dimension by dims, as shown below. The list, list1, has 3 dimensions with a maximum shape of 5, 3, 3, for each respective dimension.

print('number of dimensions', len(dims))
print('maximum shape', dims)
Output:
number of dimensions 3
maximum shape [5, 3, 3]

It’s possible that there’s a more elegant way to do this. Still, I think this example does a good job of illustrating the complexities of Python list and tuple shapes.

Full Script

def set_dimension(dims, index, value):
    if len(dims) > index:
        if dims[index] < value:
            dims[index] = value
    else:
        dims.append(value)
    return dims

list1 = [[1, 2, 3], [1, 2], [[2, 3, 4], [1, 3], 1], 9, [1, 2, 3]]

dims = []
set_dimension(dims, 0, len(list1))
print(dims)

for i in range(len(list1)):
    if isinstance(list1[i], list):
        dims = set_dimension(dims, 1, len(list1[i]))
        for j in range(len(list1[i])):
            if isinstance(list1[i][j], list):
                dims = set_dimension(dims, 2, len(list1[i][j]))
                for k in range(len(list1[i][j])):
                    if isinstance(list1[i][j][k], list):
                        dims = set_dimension(dims, 3, len(list1[i][j][k]))
                        print('four dimensions')
print('number of dimensions', len(dims))
print('maximum shape', dims)

Conclusion

As you now know, nested lists and tuples can be quite complex because they contain few structural regulations. This is the reason that other Python data structures, like dictionaries, data frames, and arrays exist. If you need to find the dimensions and shapes of complex lists and tuples, this tutorial has demonstrated how you can do that. However, if you can use another data structure instead of a nested array your life, and code, will probably be much simpler.

Similar Posts