24

Simple question here:

I'm trying to get an array that alternates values (1, -1, 1, -1.....) for a given length. np.repeat just gives me (1, 1, 1, 1,-1, -1,-1, -1). Thoughts?

1
  • How about strides or views? Is it possible? Commented Aug 23, 2011 at 2:11

7 Answers 7

30

I like @Benjamin's solution. An alternative though is:

import numpy as np
a = np.empty((15,))
a[::2] = 1
a[1::2] = -1

This also allows for odd-length lists.

EDIT: Also just to note speeds, for a array of 10000 elements

import numpy as np
from timeit import Timer

if __name__ == '__main__':

    setupstr="""
import numpy as np
N = 10000
"""

    method1="""
a = np.empty((N,),int)
a[::2] = 1
a[1::2] = -1
"""

    method2="""
a = np.tile([1,-1],N)
"""

    method3="""
a = np.array([1,-1]*N)   
"""

    method4="""
a = np.array(list(itertools.islice(itertools.cycle((1,-1)), N)))    
"""
    nl = 1000
    t1 = Timer(method1, setupstr).timeit(nl)
    t2 = Timer(method2, setupstr).timeit(nl)
    t3 = Timer(method3, setupstr).timeit(nl)
    t4 = Timer(method4, setupstr).timeit(nl)

    print 'method1', t1
    print 'method2', t2
    print 'method3', t3
    print 'method4', t4

Results in timings of:

method1 0.0130500793457
method2 0.114426136017
method3 4.30518102646
method4 2.84446692467

If N = 100, things start to even out but starting with the empty numpy arrays is still significantly faster (nl changed to 10000)

method1 0.05735206604
method2 0.323992013931
method3 0.556654930115
method4 0.46702003479

Numpy arrays are special awesome objects and should not be treated like python lists.

Sign up to request clarification or add additional context in comments.

6 Comments

+1: This is quite fast, most likely the best way to do it with numpy.
You could also use a = np.ones(15) instead of empty and =1.
@DSM that's another possibility, but in my tests it's still a bit slower than the solution I posted (but still faster than everything else). I discovered this fill trick a while back and am still not sure why it is often faster than the more straightforward/intuitive solution. I'm a big fan of timeit since it is an objective arbiter .
@JoshAdel: Yes timeit is objective in some sense but remember that python is often written for simplicity and readability rather than speed alone! Especially if you don't have a real reason to optimize for CPU time or memory, I'd say stick with the more commonplace, readable solution such as a list comprehension or cycle: you and others may appreciate it in the future.
@JoshAdel: Well I'll defer to you for that then, because I'm no numpy expert, but for the record it was the define/iterslice/reiterslice combo that bugged me, not the numpy function. I think numpy.ones() would be better just because you only have to slice the array once, which is more readable simply because it's only two statements and you're getting straight to the point. I agree that your solution is very readable and a clever one, that's why it got my upvote, but that doesn't mean it's perfect! :)
|
18

use resize():

In [38]: np.resize([1,-1], 10) # 10 is the length of result array
Out[38]: array([ 1, -1,  1, -1,  1, -1,  1, -1,  1, -1])

it can produce odd-length array:

In [39]: np.resize([1,-1], 11)
Out[39]: array([ 1, -1,  1, -1,  1, -1,  1, -1,  1, -1,  1])

Comments

9

Use numpy.tile!

import numpy
a = numpy.tile([1,-1], 15)

2 Comments

Doesn't allow for odd-length lists
Lol not from me! Someone was just pissed off or something?
7

If you want a memory efficient solution, try this:

def alternator(n):
    for i in xrange(n):
        if i % 2 == 0:
            yield 1
        else:
            yield -1

Then you can iterate over the answers like so:

for i in alternator(n):
    # do something with i

3 Comments

I'm not the downvoter, but I'd imagine it's because it doesn't make sense to re-implement itertools.islice(itertools.cycle((1,-1)), n).
+1 Well you get my upvote because it's original and efficient! It's always nice to see an original implementation of something in a library so you can see the inner workings of it. Could probably be a bit more general, but meh. Good job incorporating odd-length too. Definitely not worth a down-vote.
agf, that's yet another way. My implementation wasn't overly verbose, or overly terse, or wasteful, and showed the OP how to do things a bit differently. It wasn't dumb. machine yearning: thanks
6

use multiplication:

[1,-1] * n

2 Comments

Or *(int)(n/2) if you want n to be the length of list.
Doesn't allow for odd-length lists
4

Maybe you're looking for itertools.cycle?

list_ = (1,-1,2,-2)  # ,3,-3, ...

for n, item in enumerate(itertools.cycle(list_)):
    if n==30:
        break

    print item

Comments

1

I'll just throw these out there because they could be more useful in some circumstances.

If you just want to alternate between positive and negative:

[(-1)**i for i in range(n)]

or for a more general solution

nums = [1, -1, 2]
[nums[i % len(nums)] for i in range(n)]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.