Recipe 4.8. Transposing Two-Dimensional ArraysCredit: Steve Holden, Raymond Hettinger, Attila Vàsàrhelyi, Chris Perkins ProblemYou need to transpose a list of lists, turning rows into columns and vice versa. SolutionYou must start with a list whose items are lists all of the same length, such as: arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]] A list comprehension offers a simple, handy way to transpose such a two-dimensional array: print [[r[col] for r in arr] for col in range(len(arr[0]))] [[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]] A faster though more obscure alternative (with exactly the same output) can be obtained by exploiting built-in function zip in a slightly strange way: print map(list, zip(*arr)) DiscussionThis recipe shows a concise yet clear way to turn rows into columns, and also a faster though more obscure way. List comprehensions work well when you want to be clear yet concise, while the alternative solution exploits the built-in function zip in a way that is definitely not obvious. Sometimes data just comes at you the wrong way. For instance, if you use Microsoft's ActiveX Data Ojbects (ADO) database interface, due to array element-ordering differences between Python and Microsoft's preferred implementation language (Visual Basic), the Getrows method actually appears to return database columns in Python, despite the method's name. This recipe's two solutions to this common kind of problem let you choose between clarity and speed. In the list comprehension solution, the inner comprehension varies what is selected from (the row), while the outer comprehension varies the selector (the column). This process achieves the required transposition. In the zip-based solution, we use the *a syntax to pass each item (row) of arr to zip, in order, as a separate positional argument. zip returns a list of tuples, which directly achieves the required transposition; we then apply list to each tuple, via the single call to map, to obtain a list of lists, as required. Since we don't use zip's result as a list directly, we could get a further slight improvement in performance by using itertools.izip instead (because izip does not materialize its result as a list in memory, but rather yields it one item at a time): import itertools print map(list, itertools.izip(*arr)) but, in this specific case, the slight speed increase is probably not worth the added complexity.
If you're transposing large arrays of numbers, consider Numeric Python and other third-party packages. Numeric Python defines transposition and other axis-swinging routines that will make your head spin. See AlsoThe Reference Manual and Python in a Nutshell sections on list displays (the other name for list comprehensions) and on the *a and *k notation for positional and named argument passing; built-in functions zip and map; Numeric Python (http://www.pfdubois.com/numpy/). |