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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With