11

[编辑] 我不确定这是否对 codereview 更好,如果是,请迁移 :) 谢谢!

所以我们坐在这里,研究一个半学术问题。

给定一个start,stopstep, 生成一个范围元组列表, 所以

gen_range(100, 140, 10)

会产生

[(100, 110), (110, 120), (120, 130), (130, 140)]

另外,考虑到它应该可以工作,比如说,以 100 的步长迭代 500M 整数,而不是永远。

我想出的实现如下:

def gen_range(start, stop, step):
    llist = range(start, stop+step, step)
    batch_list = []

    if llist[-1] > stop:
        llist[-1] = stop

    for a, b in enumerate(llist[:-1]):
        batch_list.append((llist[a], llist[a+1]))

    print batch_list

gen_range(100000000,600000000,100)

但我不能停止认为它可以以一种更有效(也是代码长度方面)的方式来完成。有什么建议么?

[编辑]

我忘了指出一件事。如果范围边界不等于步长,即您有以下情况:

gen_range(100, 143, 10)

上限应该是 143,而不是 150,因为这里的一些答案会产生,由于range()内部。

4

7 回答 7

9

一个非常短的方法:

ranges = [(n, min(n+step, stop)) for n in xrange(start, stop, step)]

更详细的方法:

也许通过发电机?

def gen_range(start, stop, step):
    current = start
    while current < stop:
        next_current = current + step
        if next_current < stop:
            yield (current, next_current)
        else:
            yield (current, stop)
        current = next_current

调用此函数会为您提供一个生成器对象,该对象将按顺序生成每个元组。你会像这样使用它:

for block in gen_range(100000000,600000000,100):
    print block

这将输出...

(100000000,100000100)
(100000100,100000200)
(100000200,100000300)
...
(599999900,600000000)

如果您始终确定它stop-start是 的偶数倍,则可以使用生成器表达式更简单地执行此操作step

ranges = ((n, n+step) for n in xrange(start, stop, step))

# Usage
for block in ranges:
    print block

还要注意,如果你想把一个生成器变成一个列表,把整个结果保存在内存中,你可以简单地将它传递给list()

all_ranges = list(gen_range(100000000,600000000,100))
于 2012-12-27T02:43:15.553 回答
2

如果(b - a) % c == 0

def gen_range(a, b, c):
    return [(i, i + c) for i in range(a, b, c)]

或者

def gen_range_2(a, b, c):
    s = range(a, b + c, c)
    return zip(s, s[1:])

http://ideone.com/VhY215

如果(b - a) % c != 0

def gen_range(a, b, c):
    return [(i, i + c) for i in range(a, b - ((b - a) % c), c)]

或者

def gen_range_2(a, b, c):
    s = range(a, b - ((b - a) % c) + c, c)
    return zip(s, s[1:])

http://ideone.com/i3Pq69

于 2012-12-27T02:44:54.667 回答
1

我认为生成器是一个很好的尝试:

def gen_range(start, stop, step):
    while start < stop:
        yield (start, min(start + step, stop))
        start = start + step

if __name__ == '__main__':
    print [x for x in gen_range(100, 143, 10)]
于 2012-12-27T04:34:53.153 回答
1

我会使用生成器方法,但是如果您要将事物解压缩到显式列表中,另一种看待它的方式是您的元组元素之间的关系非常简单,并且所有你需要做的是适当地调整长度。

def gen_range(start, stop, step):
   items = ((stop-start) // step)
   return [(start+(n*step), start+(n+1)*step) for n in range(items)]

我认为值得发布此内容的唯一原因是我的第一个想法(以及评论查询)是否可以只要求列表中的第 n 个元组而无需生成批次。如果你不能,那么我不会从这个角度走下去。

于 2012-12-27T03:24:26.613 回答
1

像这样的东西:

In [48]: it=iter(xrange(100,200,10))

In [49]: it1=iter(xrange(110,210,10))

In [50]: [(next(it),next(it1)) for _ in range(10)]
Out[50]: 
[(100, 110),
 (110, 120),
 (120, 130),
 (130, 140),
 (140, 150),
 (150, 160),
 (160, 170),
 (170, 180),
 (180, 190),
 (190, 200)]

或使用zip()

In [55]: it=iter(xrange(100,200,10))

In [56]: it1=iter(xrange(110,210,10))

In [57]: [(x,y) for x,y in zip(it,it1)]
Out[57]: 
[(100, 110),
 (110, 120),
 (120, 130),
 (130, 140),
 (140, 150),
 (150, 160),
 (160, 170),
 (170, 180),
 (180, 190),
 (190, 200)]
于 2012-12-27T02:44:12.063 回答
1

我不确定我是否正确理解了这个问题,但这可以通过列表理解简单地完成:

start = 100
stop = 140
step = 10
[ range(s,s+step+1,step) for s in range(start,stop,step)]

如果您一次只需要迭代一个列表元素,我强烈建议您改用生成器理解:

res = ( range(s,s+step+1,step) for s in range(start,stop,step))

您可以循环遍历它:

for range_piece in res:
    do_something with it
于 2012-12-27T02:45:04.597 回答
1

我会把它做成一个发电机,这样它就可以处理很大的范围。

def gen_range(start, stop, step):
    a, b = start, start+step
    while b <= stop:
        yield a, b
        a, b = b, b+step

print list(gen_range(100, 140, 10))
于 2012-12-27T02:49:09.383 回答