更新时间:2023-02-03 08:02:46
一种方法可能是逐个吃"输入序列并存储部分范围的结果,直到获得全部结果为止:
One approach could be "eating" piece by piece the input sequence and store the partial range results untill you've got them all:
def formatter(start, end, step):
return '{}-{}:{}'.format(start, end, step)
# return '{}-{}:{}'.format(start, end + step, step)
def helper(lst):
if len(lst) == 1:
return str(lst[0]), []
if len(lst) == 2:
return ','.join(map(str,lst)), []
step = lst[1] - lst[0]
for i,x,y in zip(itertools.count(1), lst[1:], lst[2:]):
if y-x != step:
if i > 1:
return formatter(lst[0], lst[i], step), lst[i+1:]
else:
return str(lst[0]), lst[1:]
return formatter(lst[0], lst[-1], step), []
def re_range(lst):
result = []
while lst:
partial,lst = helper(lst)
result.append(partial)
return ','.join(result)
我用一堆单元测试对其进行了测试,并且全部通过了测试,它也可以处理负数,但是它们看起来很难看(这实际上是任何人的错).
I test it with a bunch of unit tests and it passed them all, it can handle negative numbers too, but they'll look kind of ugly (it's really anybody's fault).
示例:
>>> re_range([1, 4,5,6, 10, 15,16,17,18, 22, 25,26,27,28])
'1,4-6:1,10,15-18:1,22,25-28:1'
>>> re_range([1, 3, 5, 7, 8, 9, 10, 11, 13, 15, 17])
'1-7:2,8-11:1,13-17:2'
注意::我为Python 3编写了代码.
Note: I wrote the code for Python 3.
在上述解决方案中,我没有付出任何性能上的努力.特别是,每次使用切片重新构建列表时,如果输入列表具有特定形状,则可能要花费一些时间.因此,第一个简单的改进就是使用 itertools.islice()
可能.
I didn't put any performance effort in the solution above. In particular, every time a list get re-builded with slicing, it might take some time if the input list has a particular shape. So, the first simple improvement would be using itertools.islice()
where possible.
无论如何,这是同一算法的另一种实现,它使用scan
索引而不是切片来扫描输入列表:
Anyway here's another implementation of the same algorithm, that scan through the input list with a scan
index instead of slicing:
def re_range(lst):
n = len(lst)
result = []
scan = 0
while n - scan > 2:
step = lst[scan + 1] - lst[scan]
if lst[scan + 2] - lst[scan + 1] != step:
result.append(str(lst[scan]))
scan += 1
continue
for j in range(scan+2, n-1):
if lst[j+1] - lst[j] != step:
result.append(formatter(lst[scan], lst[j], step))
scan = j+1
break
else:
result.append(formatter(lst[scan], lst[-1], step))
return ','.join(result)
if n - scan == 1:
result.append(str(lst[scan]))
elif n - scan == 2:
result.append(','.join(map(str, lst[scan:])))
return ','.join(result)
一旦它比以前的***解决方案快〜65%,我就停止了工作,这似乎足够:)
无论如何,我想说可能仍有改进的空间(尤其是在中间的循环中).
Anyway I'd say that there might still be room for improvement (expecially in the middle for-loop).