Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

counting up and then down a range in python

Tags:

python

I am trying to program a standard snake draft, where team A pick, team B, team C, team C, team B, team A, ad nauseum.

If pick number 13 (or pick number x) just happened how can I figure which team picks next for n number of teams.

I have something like:

def slot(n,x):
    direction = 'down' if (int(x/n) & 1) else 'up'
    spot = (x % n) + 1
    slot = spot if direction == 'up' else ((n+1) - spot)
    return slot

I have feeling there is a simpler, more pythonic what than this solution. Anyone care to take a hack at it?

So I played around a little more. I am looking for the return of a single value, rather than the best way to count over a looped list. The most literal answer might be:

def slot(n, x): # 0.15757 sec for 100,000x 
    number_range = range(1, n+1) + range(n,0, -1)
    index = x % (n*2)
    return number_range[index]

This creates a list [1,2,3,4,4,3,2,1], figures out the index (e.g. 13 % (4*2) = 5), and then returns the index value from the list (e.g. 4). The longer the list, the slower the function.

We can use some logic to cut the list making in half. If we are counting up (i.e. (int(x/n) & 1) returns False), we get the obvious index value (x % n), else we subtract that value from n+1:

def slot(n, x): # 0.11982 sec for 100,000x 
    number_range = range(1, n+1) + range(n,0, -1)
    index = ((n-1) - (x % n)) if (int(x/n) & 1) else (x % n)
    return number_range[index]

Still avoiding a list altogether is fastest:

def slot(n, x): # 0.07275 sec for 100,000x
    spot = (x % n) + 1
    slot = ((n+1) - spot) if (int(x/n) & 1) else spot
    return slot

And if I hold the list as variable rather than spawning one:

number_list = [1,2,3,4,5,6,7,8,9,10,11,12,12,11,10,9,8,7,6,5,4,3,2,1]
def slot(n, x): # 0.03638 sec for 100,000x
    return number_list[x % (n*2)]
like image 711
Cole Avatar asked Nov 19 '12 17:11

Cole


People also ask

Can Python range count down?

Can Python range count down? As discussed, the increment between two successive numbers is determined using the step parameter in the range() function. We can count down in a for loop in Python using this. For this, the start value should be greater than the end value.

How do you count items in a range in Python?

The most straightforward way to get the number of elements in a list is to use the Python built-in function len() . As the name function suggests, len() returns the length of the list, regardless of the types of elements in it.

How do you make a range go backwards in Python?

But Python does have a built-in reversed function. If you wrap range() inside reversed() , then you can print the integers in reverse order. range() makes it possible to iterate over a decrementing sequence of numbers, whereas reversed() is generally used to loop over a sequence in reverse order.


2 Answers

Why not use itertools cycle function:

from itertools import cycle
li = range(1, n+1) + range(n, 0, -1) # e.g. [1, 2, 3, 4, 4, 3, 2, 1]
it = cycle(li)

[next(it) for _ in xrange(10)] # [1, 2, 3, 4, 4, 3, 2, 1, 1, 2]

Note: previously I had answered how to run up and down, as follows:

it = cycle(range(1, n+1) + range(n, 0, -1)) #e.g. [1, 2, 3, 4, 3, 2, 1, 2, 3, ...]
like image 163
Andy Hayden Avatar answered Sep 25 '22 22:09

Andy Hayden


Here's a generator that will fulfill what you want.

def draft(n):
    while True:
        for i in xrange(1,n+1):
            yield i
        for i in xrange(n,0,-1):
            yield i

>>> d = draft(3)
>>> [d.next() for _ in xrange(12)]
[1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1]
like image 36
kreativitea Avatar answered Sep 25 '22 22:09

kreativitea