我想知道是否有一种简单的(或已经创建的)方法来做与此相反的事情:Generate List of Numbers from Hyphenated...。此链接可用于:
>> list(hyphen_range('1-9,12,15-20,23'))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 15, 16, 17, 18, 19, 20, 23]:
我希望做相反的事情(注意10和21包含在内,所以它与range函数兼容,其中range(1,10)=[1,2,3,4,5,6,7,8,9]):
>> list_to_ranges([1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 15, 16, 17, 18, 19, 20, 23])
'1-10,12,15-21,23'
最后,我希望输出也包含一个步骤,其中最后一个输出数表示该步骤:
>> list_to_ranges([1, 3, 5, 7, 8, 9, 10, 11])
'1-13:2,8,10'
从本质上讲,这会有点像一个“逆”范围函数
>> tmp = list_to_ranges([1, 3, 5])
>> print tmp
'1-7:2'
>> range(1, 7, 2)
[1, 3, 5]
我的猜测是没有真正简单的方法来做到这一点,但我想我会问在这里之前,我去做一些蛮力,长的方法。
编辑
以this post的答案中的代码为例,我想出了一个简单的方法来完成第一部分。但我认为,确定要执行步骤的模式会有点困难。
from itertools import groupby
from operator import itemgetter
data = [ 1, 4,5,6, 10, 15,16,17,18, 22, 25,26,27,28]
print data, '\n'
str_list = []
for k, g in groupby(enumerate(data), lambda (i,x):i-x):
ilist = map(itemgetter(1), g)
print ilist
if len(ilist) > 1:
str_list.append('%d-%d' % (ilist[0], ilist[-1]+1))
else:
str_list.append('%d' % ilist[0])
print '\n', ','.join(str_list)
编辑2
这里是我的尝试,包括步骤大小…这是相当接近,但第一个数字得到重复。我认为只要稍微调整一下,它就会接近我想要的——或者至少足够好。
import numpy as np
from itertools import groupby
def list_to_ranges(data):
data = sorted(data)
diff_data = np.diff(data).tolist()
ranges = []
i = 0
for k, iterable in groupby(diff_data, None):
rng = list(iterable)
step = rng[0]
if len(rng) == 1:
ranges.append('%d' % data[i])
elif step == 1:
ranges.append('%d-%d' % (data[i], data[i+len(rng)]+step))
else:
ranges.append('%d-%d:%d' % (data[i], data[i+len(rng)]+step, step))
i += len(rng)
return ','.join(ranges)
data = [1, 3, 5, 6, 7, 11, 13, 15, 16, 17, 18, 19, 22, 25, 28]
print data
data_str = list_to_ranges(data)
print data_str
_list = []
for r in data_str.replace('-',':').split(','):
r = [int(a) for a in r.split(':')]
if len(r) == 1:
_list.extend(r)
elif len(r) == 2:
_list.extend(range(r[0], r[1]))
else:
_list.extend(range(r[0], r[1], r[2]))
print _list
print list(set(_list))
This很可能就是你要找的。
编辑:我看你已经找到那篇文章了。我很抱歉。
为了帮助完成第二部分,我自己做了一些修改。这就是我想到的:
对于给定的输入列表,这将给出:
['1-7:2', '8-11:1', '13-17:2']
。代码可以进行一些清理,但如果可以按顺序进行分组,则这会解决您的问题。{注意:对于[1,2,3,5,6,7],这里给出的是['1-3:1','5-5:2','6-7:1'],而不是['1-3:1','5-7:1']}
这是三种方法的比较。通过下面的值更改数据量和密度…不管我使用什么值,第一个解决方案对我来说似乎是最快的。对于非常大的数据集,第三种解决方案变得非常缓慢。
已编辑
编辑以包含以下注释并添加新解决方案。最后的解决办法似乎是现在最快的。
一种方法是逐个“吃掉”输入序列,并存储部分范围的结果,直到得到所有结果:
我用一堆单元测试来测试它,它通过了所有的测试,它也可以处理负数,但是它们看起来有点难看(这真的是任何人的错)。
示例:
注意:我为Python3编写了代码。
性能
我没有在上面的解决方案中投入任何性能努力。特别是,每次使用切片重新构建列表时,如果输入列表具有特定形状,则可能需要一些时间。因此,第一个简单的改进是尽可能使用^{} 。
不管怎样,这里是同一算法的另一个实现,它用
scan
索引扫描输入列表,而不是切片:当它比上一个顶级解决方案快65%时,我就停止了工作:)
不管怎样,我想说可能还有改进的余地(特别是在循环中间)。
相关问题 更多 >
编程相关推荐