Create Python alternating range programmatically

Question:

I am looking for a convenient way to create an ordered, alternating (negative, positive while decrementing and incrementing by one from previous pair) list of integers in the form of

[-1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, 8, -9, 9, -10, 10]

with Python with variable length/end integer, like:
alternating_range(2) = [-1, 1, -2, 2]

I can easily do this in a "for loop" but I am looking for a more "Pythonic" way

Asked By: DaHoC

||

Answers:

You could do it as a generator like this:

def alternating_range(x):
    return (i for j in range(1, x+1) for i in (-j,j))

However, I think the for loop solution is more readable. You cite "flat is better than nested". This solution has only one level of nesting while the one above has 2.

def alternating_range(x):
    for i in range(1, x+1):
        yield -i
        yield i

Both of these return generators, you can use list(alternating_range(x)) to convert to a list.

Answered By: mousetail

Here are two possible solutions:

The first one using list comprehension:

def alternating(i : int) -> List[int]:
    return [i * sign for i in range(1, i + 1) for sign in [1, -1]]

And the second one using numpy:

import numpy as np
def alternating(i : int) -> np.ndarray:
    return np.c_[(r := np.arange(1, i)), -1 * r].reshape(-1)
Answered By: Plagon

I believe you want something fancy, if however not very efficient, like this:

def alternating_range(end):
  return list(sum(map(lambda x: (x*-1, x), range(1, end+1)), ()))

print(alternating_range(10))

No imports required, no apparent nesting (for-loop) in your code

Answered By: EvilSmurf

Another (quite ugly looking) option, using list comprehension with only one for statement is:

def alternating_range(n):
    return [
        (i + (i % 2) - int((i + 1) / 2)) * (-1)**i
        for i in range(1, 2 * n + 1)
    ]
Answered By: Matt Pitkin

For fun, use tail recursive:

def alternating_range(i, n=-1, p=1, res=[]):
    return res if i+1 == p else alternating_range(i, n-1, p+1, res+[n,p])

print(alternating_range(10))

# [-1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, 8, -9, 9, -10, 10]

or while loop:

def alternating_range(i, n=-1, p=1, res=[]):
    while p <= i: res += [n, p]; n, p = n-1, p+1
    return res

print(alternating_range(10))

# [-1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, 8, -9, 9, -10, 10]
Answered By: Arifa Chan
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.