Search code examples
pythonpython-3.xpython-itertoolssplat

zip_longest on Array with lists of the same length. Understanding


I have an Array which contains a few lists all the same length. All those lists need to be written in a .csv-file. Using a piece of code i have found it works pretty well. Here the code:

ag=[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]

export_data = zip_longest(*ag, fillvalue = '') 

with open('motion_profile.csv', 'w', encoding="ISO-8859-1", newline='') as myfile:
    wr = csv.writer(myfile, delimiter=',')
    wr.writerow(("m","ax","ay","az","sx","sy","sz"))
    wr.writerows(export_data)  
myfile.close()

I understand the basic concept of zip and zip_longest when i have two arrays which i use it on. But i just can't wrap my head around what it does with a single array like here export_data = zip_longest(*ag, fillvalue = '')

What exactly happens to ag if i use zip or zip_longest on it?

Since i don't have two arrays what does it zip against?

zip_longest is being applied to each list in ag hence the *. That is how far I have gotten with it.

Could anyone walk me through that?


Solution

  • zip() does not necessarily take two arrays; it takes an arbitrary number of arrays (iterables) as positional arguments.

    Taking this in smaller steps,

    • *ag unpacks the nested list. Note that it only unpacks "one level down." You're effectively left with 4 lists, [1, 2, 3], ... [10, 11, 12], as disparate elements that will become positional arguments.
    • From there, zip() behaves as expected (you're passing it multiple unpacked lists).

    You can see the equivalency:

    >>> i, j, k = zip(*ag)
    
    >>> i
    (1, 4, 7, 10)
    >>> k
    (3, 6, 9, 12)
    
    >>> i2, j2, k2 = zip([1,2,3],[4,5,6],[7,8,9],[10,11,12])
                    #     |_______|_______|________|
                    #                 i2
    
    >>> i2
    (1, 4, 7, 10)
    >>> k2
    (3, 6, 9, 12)
    

    In other words, those four sub-lists are passed as four positional arguments to zip().

    In terms of the call syntax, itertools.zip_longest(*iterables, fillvalue=None) is pretty similar; it just has one keyword argument tacked on to the end. The way in which the sub-lists are passed is effectively the same.