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?
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?
Explanation:
This code picks numbers from the beginning (
a[i//2]
) and from the end (a[-i//2]
) ofa
, alternatingly (if i%2 else
). A total oflen(a)
numbers are picked, so this produces no ill effects even iflen(a)
is odd.[-i//2 for i in range(len(a))]
yields0, -1, -1, -2, -2, -3, -3, -4, -4, -5
,[ i//2 for i in range(len(a))]
yields0, 0, 1, 1, 2, 2, 3, 3, 4, 4
,and
i%2
alternates betweenFalse
andTrue
,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 asi//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.
The basic principle behind your question is a so-called roundrobin algorithm. The
itertools
-documentation-page contains a possible implementation of it:so all you have to do is split your list into two sublists one starting from the left end and one from the right end:
alternatively you could create a longer list (containing alternating items from sequence going from left to right and the items of the complete sequence going right to left) and only take the relevant elements:
or using it as explicit generator with
next
:or the speedy variant suggested by @Tadhg McDonald-Jensen (thank you!):
Not terribly different from some of the other answers, but it avoids a conditional expression for determining the sign of the index.
i & 1
alternates between 0 and 1. This causes the exponent to alternate between 1 and -1. This causes the index divisor to alternate between 2 and -2, which causes the index to alternate from end to end asi
increases. The sequence isa[0]
,a[-1]
,a[1]
,a[-2]
,a[2]
,a[-3]
, etc.(I iterate
i
overa
since in this case each value ofa
is equal to its index. In general, iterate overrange(len(a))
.)Two versions not seen yet:
and
I would do something like this
A very nice one-liner in Python 2.7:
First you zip the list with its reverse, take half that list, sum the tuples to form one tuple, and then convert to list.
In Python 3,
zip
returns a generator, so you have have to useislice
fromitertools
:Edit: It appears this only works perfectly for even-list lengths - odd-list lengths will omit the middle element :( A small correction for
int(len(a)/2)
toint(len(a)/2) + 1
will give you a duplicate middle value, so be warned.