Question

Is there a way to slice a list every few items and then reverse them?
For example, can I turn:

1 2 3 4 5 6 7 8 9

into:

7 8 9 4 5 6 1 2 3

Is there a simple slice notation that could accomplish this goal similar to list[::-1] used to reverse the list?

Was it helpful?

Solution

There isn't a slice notation for this, here is how I would probably do it (this is with Python 2.x, Python 3.x code is included at the end):

>>> lst = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [x for s in reversed(zip(*[iter(lst)]*3)) for x in s]
[7, 8, 9, 4, 5, 6, 1, 2, 3]

This method for clustering elements into n length groups comes straight from the zip docs, so the approach here is to create your groups of 3, reverse the resulting list, and then use a list comprehension for flattening.

Or with the itertools module, using the grouper recipe and chain.from_iterable:

from itertools import izip_longest, chain

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9]
result = list(chain.from_iterable(reversed(list(grouper(lst, 3)))))

Python 3 versions:

For the first approach you will need to convert the generator returned by zip to a list, otherwise reversed will fail:

>>> [x for s in reversed(list(zip(*[iter(lst)]*3))) for x in s]
[7, 8, 9, 4, 5, 6, 1, 2, 3]

And in the itertools approach you just need to replace izip_longest with zip_longest in both the import statement and inside of the grouper function.

OTHER TIPS

numpy can make something like this easy for you:

>>> import numpy as np
>>> a = np.arange(1, 10)
>>> result = a.reshape((3, -1))[::-1].ravel() #if you OK with getting np.array
>>> result
array([7, 8, 9, 4, 5, 6, 1, 2, 3]) 

If you want a list

>>> result = a.reshape((3, -1))[::-1].ravel().tolist() #if you want to get back a list
>>> result
[7, 8, 9, 4, 5, 6, 1, 2, 3]

This solution only works if a list can be divided into n equal parts.

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

reversed_by_group = [el for sublist in list(reversed(list(zip(*[iter(lst)]*QTYPERGROUP)))) for el in sublist]
# [7, 8, 9, 4, 5, 6, 1, 2, 3]

It's long and ugly, but it does the job. Note that this only works if len(lst) % QTYPERGROUP == 0, otherwise it will ignore the rest. For example

QTYPERGROUP = 4
reversed_by_group = [el for sublist in list(reversed(list(zip(*[iter(lst)]*QTYPERGROUP)))) for el in sublist]
# [5, 6, 7, 8, 1, 2, 3, 4] there's no "9"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top