Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adjust all nested lists to the same length

I am referring to this this specific answer Making nested lists same length. Since I don't have the permissions to comment yet and answering with a question to that topic would violate the rules, I am asking a new question.

I don't fully understand the answer. In my understanding the iterator row in the for-loop is usually an integer value which iterates over each element in myList. So how is it possible to use len(row) as part of the condition since it is just an integer? Is there something I am missing?

I have tried to apply this solution to my code but as expected I receive an error saying

TypeError: object of type 'int' has no len()
 args = ("object of type 'int' has no len()",)
 with_traceback = <built-in method with_traceback of TypeError object> 

referring to this line

row.extend(['null'*(len(maxSS7) - len(row))])

Further I don't understand the use of .extend with row which is the iterator and not a list.

Here is the relevant part from the answer.

maxLen = max(map(len, myList))
for row in myList:
    if len(row) < maxLen:
        row.extend(...)

A brief walkthrough would be greatly appreciated.

Or maybe there is a better way to adjust the lengths of all nested list to same length.

like image 587
McMo Avatar asked Feb 06 '18 07:02

McMo


1 Answers

Ok, lets go through it line by line. Personally I don't think map is very idiomatic in Python so I would write this:

maxLen = max(map(len, myList))

As a generator expresion:

max_len = max(len(item) for item in my_list)

The second version is almost plain English: let max_len be the maximum value among the length of each item in my_list.

The best way to understand something in Python is just fire up the REPL and try it. So if you have my_list as a list of lists:

my_list = [[1], [1, 2], [1, 2, 3]]

The above will get you the length of the largest item: 3

Now you want to make every item the same size. How can you do that? One way is to append None items to it. For each item in the list, you test if the length of the item is smaller then the largest item in the list and it is almost plain English:

for item in list:                # for each item in the list
    while len(item) < max_len:   # while the item length is smaller than 3
        item.append(None)        # append None to the item

You may want to do a bit of premature optimization and call extend once instead of calling append several times because you think performance will be better this way (but you can't really tell it unless you have profiled both solutions):

for item in list:
    if len(item) < max_len:
        item.extend([None] * (max_len - len(item)))

Now what is going on here? In Python, list + list concatenates two copies of list, and list * 3 is the same as list + list + list. So in the first iteration of the for loop, item is [1], len(item) is 1 and max_len - len(item) is 3 - 1. Finally, [None] * 2 is [None, None] so after the call to extend the first item will be [1, None, None]. Same thing for the second item, its length is 2, 3 minus 2 is one and it will end up as [1, 2, None]. The 3rd item has the same length as max_len (3) so the if condition is false. The result will be:

[[1, None, None], [1, 2, None], [1, 2, 3]]

All lists in the list of lists now have the same size, 3. For the sake of completion, for such a small list the extend version is less than 1 microsecond faster than the append one so barely worth the trouble (1.64 µs versus 1.7 µs in Python 3.6 running on my Mac).

like image 72
Paulo Scardine Avatar answered Oct 19 '22 13:10

Paulo Scardine