1

Given the following list of lists:

iters=[['EY11', 'EY12', 'EY13', 'EY14'],
       ['EY21', 'EY22', 'EY23', 'EY24'],
       ['PY11', 'PY12', 'PY13', 'PY14'],
       ['PY21', 'PY22', 'PY23', 'PY24']]

I'd like to modify this list to transpose the values (for lack of a better description) like this:

iters=[['EY11', 'EY21', 'PY11', 'PY21'],
       ['EY12', 'EY22', 'PY12', 'PY22'],
       ['EY13', 'EY23', 'PY13', 'PY23'],
       ['EY14', 'EY24', 'PY14', 'PY24']]

I can do this with one sub-list at a time like this:

[i[0] for i in iters]

but now I just need to know how to iterate through each sub-list and automatically make the new list of lists (also, I can't predict how many sub-lists there will be in my actual data, so I'd like to avoid hard-coding the current number of sub-lists in i[0].

Thanks in advance!

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
Dance Party2
  • 7,214
  • 17
  • 59
  • 106

4 Answers4

4

Most concise solution is to use the zip function with star unpacking:

newiters = list(zip(*iters))  # Wrapping in list not needed on Python 2

This will get almost what you want, but not quite, because it will be a list of tuples; if that's okay, you're done, if not, you just tweak it to convert to lists:

newiters = list(map(list, zip(*iters)))  # Wrapping in list not needed on Python 2

Reason this works is that star unpacking makes it as if you passed each element of iters as a sequential positional argument to zip, e.g.:

zip(['EY11', 'EY12', 'EY13', 'EY14'],
    ['EY21', 'EY22', 'EY23', 'EY24'],
    ['PY11', 'PY12', 'PY13', 'PY14'],
    ['PY21', 'PY22', 'PY23', 'PY24'])

And zip's whole schtick is making new tuples of values from matching offsets in a set of iterables, so the first tuple is the first element of each argument (('EY11', 'EY21', 'PY11', 'PY21')), the second is the second element of each argument (('EY12', 'EY22', 'PY12', 'PY22')), etc.

Note: This assumes all sub-lists are the same length. You'll lose data if they aren't, because zip stops when the shortest iterable is exhausted. You can use itertools.zip_longest to pad out shorter iterables to the length of the longest iterable if you like.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
1

Do you mean something like this:

iters=[['EY11', 'EY12', 'EY13', 'EY14'],
       ['EY21', 'EY22', 'EY23', 'EY24'],
       ['PY11', 'PY12', 'PY13', 'PY14'],
       ['PY21', 'PY22', 'PY23', 'PY24']]


def iterating(iters):
    if len(iters) > 0:
        range_len = len(iters[0]) 
        ret = []
        for idx in range(0,range_len):
            ret.append([i[idx] for i in iters])
        return ret
    return None

if __name__ == '__main__':
    print iterating(iters)

will output to:

[['EY11', 'EY21', 'PY11', 'PY21'], ['EY12', 'EY22', 'PY12', 'PY22'], ['EY13', 'EY23', 'PY13', 'PY23'], ['EY14', 'EY24', 'PY14', 'PY24']]

The function is not fixed size but id does assume that all the lists within the list are the same size.

Ivonet
  • 2,492
  • 2
  • 15
  • 28
1

Here's a one liner using list comprehension.

transp = [[i[x] for i in iters] for x in range(0,4)]

Basically what you did except iterates through the indexes.

#Output
['EY11', 'EY21', 'PY11', 'PY21']
['EY12', 'EY22', 'PY12', 'PY22']
['EY13', 'EY23', 'PY13', 'PY23']
['EY14', 'EY24', 'PY14', 'PY24']
Jeremy
  • 818
  • 6
  • 19
1

If this is the only complex operation you need to perform on the array, then one of the other solutions is probably best. However, if you don't mind bringing in numpy, then there is a built-in routine for this called transpose.

import numpy as np
iters_np = np.array(iters).transpose()
print(iters_np)

>>>[['EY11' 'EY21' 'PY11' 'PY21']
>>> ['EY12' 'EY22' 'PY12' 'PY22']
>>> ['EY13' 'EY23' 'PY13' 'PY23']
>>> ['EY14' 'EY24' 'PY14' 'PY24']]
Chris Mueller
  • 6,490
  • 5
  • 29
  • 35