如何生成交替范围?

时间:2010-12-31 12:34:40

标签: python

我需要在给定半径的给定索引周围的列表中搜索项目。目前,我使用此功能为搜索生成交替的偏移量:

def generateSearchIndizes(radius):
    for i in range(1, radius + 1):
        yield i
        yield -i

执行搜索的代码如下所示:

for i in generateSearchIndizes():
    if pred(myList[baseIndex + i]):
        result = myList[baseIndex + i]
        break # terminate search when first item is found

我的问题是,是否有更优雅的方式来生成搜索indizes,可能没有定义特殊功能?

7 个答案:

答案 0 :(得分:4)

  

是否有更优雅的方式来生成搜索索引

我认为没有更优雅的方式。您的代码非常简单明了。

  

可能没有定义特殊功能吗?

是的,这绝对是可能的。

>>> [b for a in ((x,-x) for x in range(1, 10 + 1)) for b in a]
[1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10]

答案 1 :(得分:2)

这是我的理由:

from itertools import chain

>>> list(chain(*zip(range(1, 7), range(-7, 0)[::-1])))
[1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6]

根据需要进行调整。 :)

答案 2 :(得分:0)

也许是一个生成器表达式?

for i in (x/2 * (x%2 * 2 - 1) for x in xrange(2, radius*2)):
    print i

它很短,适合你的“没有定义特殊功能”的要求......

但是,坦率地说,我仍然更喜欢使用那个特殊功能 - 只是为了拥有更清晰的代码。 :)

答案 3 :(得分:0)

为什么不用内循环来做这件事,而不是创建一个时髦的生成器:

found = False
for i_abs in range(1, radius+1):
    for i in (i_abs, -i_abs):
        listitem = myList[baseIndex + i]
        if pred(listitem):
             result = listitem
             found = True
             break # terminate search when first item is found 
    if found:
        break
else:
    # handling in case no match found for pred

其他一些评论:

  • 你永远不会测试第0个元素

  • 因为你是从左边开始测试的 而且,你应该停下来 i_abs达到了中途标记

  • 我不喜欢重复列表索引操作, 宁可重复变量引用;所以我 解除了重复的myList[baseIndex+i]和 已将其分配给listitem

  • 你应该添加一些处理以防万一 找不到匹配的元素

  • 而不是从内循环中断( 这里需要额外的found变量 你可能会突破外围的for循环) 最好只是从...返回result 内环,

如:

for i_abs in range(1, radius+1):
    for i in (i_abs, -i_abs):
        listitem = myList[baseIndex + i]
        if pred(listitem):
             return listitem

然后没有需要中断管理或found变量。

答案 4 :(得分:0)

为什么交替-i,我?只是做:

for i in range(-radius, radius+1):
    listitem = myList[baseIndex + i]
        if pred(listitem):
            return listitem  

或者,如果你必须从正面和背面接近以获得最外层的预先匹配,那么:

for i in sorted(range(-radius, radius+1), key=abs):
    listitem = myList[baseIndex + i]
        if pred(listitem):
            return listitem  

如果您经常这样做,只需构建sorted(range(-radius,radius+1),key=abs)一次并保留它以备将来迭代。

如果你绝对不能使用第0个元素,只需在循环开始时插入if not i: continue

答案 5 :(得分:0)

这在我看来至少与单独的功能一样可读 - 并且可以说更容易理解:

radius = 3
for outerbounds in ((-r,r) for r in range(1,radius+1)):
    for i in outerbounds :
        print i
# -1
# 1
# -2
# 2
# -3
# 3

答案 6 :(得分:0)

您自己的解决方案,在生成器的开头添加yield 0,是最直接的(也称为pythonic)。

这是一个使用不同算法的无限偏移生成器:

def gen_offsets():
    offset= 0
    yield offset
    step= 1; sign= 1
    while 1:
        offset+= sign*step
        yield offset
        step+= 1; sign= -sign

编写上述算法的更奇怪(又名不那么pythonic :)的方法是:

import itertools as it, operator as op

def gen_offsets():
    steps= it.imap(op.mul, it.count(1), it.cycle( (1, -1) ))
    offset= 0
    yield offset
    for step in steps:
        offset+= step
        yield offset