Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cycle a list from alternating sides

Given a list

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

how can I get

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

That is, produce a new list in which each successive element is alternately taken from the two sides of the original list?

like image 872
Pythonic Avatar asked Apr 10 '16 18:04

Pythonic


People also ask

How do you print two lists in Python?

You can use the zip() function to join lists together. The zip() function will iterate tuples with the corresponding elements from each of the lists, which you can then format as Michael Butscher suggested in the comments. Finally, just join() them together with newlines and you have the string you want.


2 Answers

>>> [a[-i//2] if i % 2 else a[i//2] for i in range(len(a))] [0, 9, 1, 8, 2, 7, 3, 6, 4, 5] 

Explanation:
This code picks numbers from the beginning (a[i//2]) and from the end (a[-i//2]) of a, alternatingly (if i%2 else). A total of len(a) numbers are picked, so this produces no ill effects even if len(a) is odd.
[-i//2 for i in range(len(a))] yields 0, -1, -1, -2, -2, -3, -3, -4, -4, -5,
[ i//2 for i in range(len(a))] yields 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
and i%2 alternates between False and True,
so the indices we extract from a are: 0, -1, 1, -2, 2, -3, 3, -4, 4, -5.

My assessment of pythonicness:
The nice thing about this one-liner is that it's short and shows symmetry (+i//2 and -i//2).
The bad thing, though, is that this symmetry is deceptive:
One might think that -i//2 were the same as i//2 with the sign flipped. But in Python, integer division returns the floor of the result instead of truncating towards zero. So -1//2 == -1.
Also, I find accessing list elements by index less pythonic than iteration.

like image 91
Norman Avatar answered Oct 01 '22 01:10

Norman


cycle between getting items from the forward iter and the reversed one. Just make sure you stop at len(a) with islice.

from itertools import islice, cycle  iters = cycle((iter(a), reversed(a))) b = [next(it) for it in islice(iters, len(a))]  >>> b [0, 9, 1, 8, 2, 7, 3, 6, 4, 5] 

This can easily be put into a single line but then it becomes much more difficult to read:

[next(it) for it in islice(cycle((iter(a),reversed(a))),len(a))] 

Putting it in one line would also prevent you from using the other half of the iterators if you wanted to:

>>> iters = cycle((iter(a), reversed(a))) >>> [next(it) for it in islice(iters, len(a))] [0, 9, 1, 8, 2, 7, 3, 6, 4, 5] >>> [next(it) for it in islice(iters, len(a))] [5, 4, 6, 3, 7, 2, 8, 1, 9, 0] 
like image 32
Tadhg McDonald-Jensen Avatar answered Oct 01 '22 01:10

Tadhg McDonald-Jensen