Transpose list of lists

前端 未结 12 1604
旧巷少年郎
旧巷少年郎 2020-11-21 13:33

Let\'s take:

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

The result I\'m looking for is

r = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
         


        
12条回答
  •  孤独总比滥情好
    2020-11-21 13:50

    Methods 1 and 2 work in Python 2 or 3, and they work on ragged, rectangular 2D lists. That means the inner lists do not need to have the same lengths as each other (ragged) or as the outer lists (rectangular). The other methods, well, it's complicated.

    the setup

    import itertools
    import six
    
    list_list = [[1,2,3], [4,5,6, 6.1, 6.2, 6.3], [7,8,9]]
    

    method 1 — map(), zip_longest()

    >>> list(map(list, six.moves.zip_longest(*list_list, fillvalue='-')))
    [[1, 4, 7], [2, 5, 8], [3, 6, 9], ['-', 6.1, '-'], ['-', 6.2, '-'], ['-', 6.3, '-']]
    

    six.moves.zip_longest() becomes

    • itertools.izip_longest() in Python 2
    • itertools.zip_longest() in Python 3

    The default fillvalue is None. Thanks to @jena's answer, where map() is changing the inner tuples to lists. Here it is turning iterators into lists. Thanks to @Oregano's and @badp's comments.

    In Python 3, pass the result through list() to get the same 2D list as method 2.


    method 2 — list comprehension, zip_longest()

    >>> [list(row) for row in six.moves.zip_longest(*list_list, fillvalue='-')]
    [[1, 4, 7], [2, 5, 8], [3, 6, 9], ['-', 6.1, '-'], ['-', 6.2, '-'], ['-', 6.3, '-']]
    

    The @inspectorG4dget alternative.


    method 3 — map() of map()broken in Python 3.6

    >>> map(list, map(None, *list_list))
    [[1, 4, 7], [2, 5, 8], [3, 6, 9], [None, 6.1, None], [None, 6.2, None], [None, 6.3, None]]
    

    This extraordinarily compact @SiggyF second alternative works with ragged 2D lists, unlike his first code which uses numpy to transpose and pass through ragged lists. But None has to be the fill value. (No, the None passed to the inner map() is not the fill value. It means there is no function to process each column. The columns are just passed through to the outer map() which converts them from tuples to lists.

    Somewhere in Python 3, map() stopped putting up with all this abuse: the first parameter cannot be None, and ragged iterators are just truncated to the shortest. The other methods still work because this only applies to the inner map().


    method 4 — map() of map() revisited

    >>> list(map(list, map(lambda *args: args, *list_list)))
    [[1, 4, 7], [2, 5, 8], [3, 6, 9]]   // Python 2.7
    [[1, 4, 7], [2, 5, 8], [3, 6, 9], [None, 6.1, None], [None, 6.2, None], [None, 6.3, None]] // 3.6+
    

    Alas the ragged rows do NOT become ragged columns in Python 3, they are just truncated. Boo hoo progress.

提交回复
热议问题