私はこれを少し複雑にしすぎていることに気づきました。少し複雑なジェネレーターを使用するよりも、手動で数える方がはるかに簡単です。
def ranges(seq):
start, end = seq[0], seq[0]
count = start
for item in seq:
if not count == item:
yield start, end
start, end = item, item
count = item
end = item
count += 1
yield start, end
print(list(ranges([1,2,3,4,5,8,9,10,11,200,201,202])))
生産:
[(1, 5), (8, 11), (200, 202)]
この方法はかなり高速です。
この方法(および古い方法では、ほとんど同じように機能します):
python -m timeit -s "from test import ranges" "ranges([1,2,3,4,5,8,9,10,11,200,201,202])"
1000000 loops, best of 3: 0.47 usec per loop
ジェフメルカードの方法:
python -m timeit -s "from test import as_range; from itertools import groupby, count" "[as_range(g) for _, g in groupby([1,2,3,4,5,8,9,10,11,200,201,202], key=lambda n, c=count(): n-next(c))]"
100000 loops, best of 3: 11.1 usec per loop
これは20倍以上高速ですが、当然のことながら、速度が重要でない限り、これは実際の問題ではありません。
ジェネレーターを使用した私の古いソリューション:
import itertools
def resetable_counter(start):
while True:
for i in itertools.count(start):
reset = yield i
if reset:
start = reset
break
def ranges(seq):
start, end = seq[0], seq[0]
counter = resetable_counter(start)
for count, item in zip(counter, seq): #In 2.x: itertools.izip(counter, seq)
if not count == item:
yield start, end
start, end = item, item
counter.send(item)
end = item
yield start, end
print(list(ranges([1,2,3,4,5,8,9,10,11,200,201,202])))
生産:
[(1, 5), (8, 11), (200, 202)]