简体   繁体   English

在python中向上计数然后向下计算一个范围

[英]counting up and then down a range in 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. 我正在尝试编制一个标准的蛇选项,其中A队选秀,B队,C队,C队,B队,A队,恶心。

If pick number 13 (or pick number x) just happened how can I figure which team picks next for n number of teams. 如果选秀号码13(或选秀号码x)刚刚发生,我怎样才能确定哪支球队接下来会选择n队。

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. 我觉得有一个比这个解决方案更简单,更pythonic的东西。 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 (eg 13 % (4*2) = 5), and then returns the index value from the list (eg 4). 这会创建一个列表[1,2,3,4,4,3,2,1],计算出索引(例如13%(4 * 2)= 5),然后从列表中返回索引值(例如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 (ie (int(x/n) & 1) returns False), we get the obvious index value (x % n), else we subtract that value from n+1: 如果我们正在计数(即(int(x/n) & 1)返回False),我们得到明显的索引值(x%n),否则我们从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)]

Why not use itertools cycle function: 为什么不使用itertools cycle函数:

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, ...]

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]
from itertools import chain, cycle

def cycle_up_and_down(first, last):
    up = xrange(first, last+1, 1)
    down = xrange(last, first-1, -1)
    return cycle(chain(up, down))

turns = cycle_up_and_down(1, 4)
print [next(turns) for n in xrange(10)] # [1, 2, 3, 4, 4, 3, 2, 1, 1, 2]

Here is a list of numbers that counts up, then down: 这是一个数字列表,然后向下计数:

>>> [ -abs(5-i)+5 for i in range(0,10) ]
[0, 1, 2, 3, 4, 5, 4, 3, 2, 1]

Written out: 写出来:

count_up_to = 5
for i in range( 0, count_up_to*2 ):
  the_number_you_care_about = -abs(count_up_to-i) + count_up_to
  # do stuff with the_number_you_care_about

Easier to read: 更易于阅读:

>>> list( range(0,5) ) + list( range( 5, 0, -1 ) )
[0, 1, 2, 3, 4, 5, 4, 3, 2, 1]

Written out: 写出来:

count_up_to = 5
for i in list( range(0,5) ) + list( range(5, 0, -1) ):
  # i is the number you care about

Another way: 其他方式:

from itertools import chain
for i in chain( range(0,5), range(5,0,-1) ):
  # i is the number you care about

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM