Pythonic - 1 year ago 58

Python Question

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?

Answer

```
>>> [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.