converting a list of integers into range in python
python中是否存在可以将递增的整数列表转换为范围列表的内容?
例如,给定集合0,1,2,3,4,7,8,9,11我想得到0,4,7,9,11,11。
我可以编写一个程序来实现这一点,但我想知道在Python中是否有内置函数
使用
1 2 3 4 5 6 7 8 | import itertools def ranges(i): for a, b in itertools.groupby(enumerate(i), lambda (x, y): y - x): b = list(b) yield b[0][1], b[-1][1] print list(ranges([0, 1, 2, 3, 4, 7, 8, 9, 11])) |
。
输出:
1 | [(0, 4), (7, 9), (11, 11)] |
可以将列表理解与生成器表达式以及enumerate()和itertools.groupby()的组合一起使用:
1 2 3 4 5 | >>> import itertools >>> l = [0, 1, 2, 3, 4, 7, 8, 9, 11] >>> [[t[0][1], t[-1][1]] for t in ... (tuple(g[1]) for g in itertools.groupby(enumerate(l), lambda (i, x): i - x))] [[0, 4], [7, 9], [11, 11]] |
。
首先,
1 2 | >>> [t for t in enumerate(l)] [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 7), (6, 8), (7, 9), (8, 11)] |
。
然后,
1 2 | >>> [tuple(g[1]) for g in itertools.groupby(enumerate(l), lambda (i, x): i - x)] [((0, 0), (1, 1), (2, 2), (3, 3), (4, 4)), ((5, 7), (6, 8), (7, 9)), ((8, 11),)] |
从那里,我们只需要从每个组的第一个和最后一个元组的值构建列表(如果组只包含一个项,那么列表是相同的)。
您还可以使用
这是对Juanchopanza答案非常优雅的改进。这一个包含非唯一和非排序输入,并且与python3兼容:
1 2 3 4 5 6 7 8 | import itertools def to_ranges(iterable): iterable = sorted(set(iterable)) for key, group in itertools.groupby(enumerate(iterable), lambda t: t[1] - t[0]): group = list(group) yield group[0][1], group[-1][1] |
号
例子:
1 2 3 4 5 | >>> x [44, 45, 2, 56, 23, 11, 3, 4, 7, 9, 1, 2, 2, 11, 12, 13, 45] >>> print( list(to_ranges(x))) [(1, 4), (7, 7), (9, 9), (11, 13), (23, 23), (44, 45), (56, 56)] |
号
发电机:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def ranges(p): q = sorted(p) i = 0 for j in xrange(1,len(q)): if q[j] > 1+q[j-1]: yield (q[i],q[j-1]) i = j yield (q[i], q[-1]) sample = [0, 1, 2, 3, 4, 7, 8, 9, 11] print list(ranges(sample)) print list(ranges(reversed(sample))) print list(ranges([1])) print list(ranges([2,3,4])) print list(ranges([0,2,3,4])) print list(ranges(5*[1])) |
号
产生这些结果:
1 2 3 4 5 6 | [(0, 4), (7, 9), (11, 11)] [(0, 4), (7, 9), (11, 11)] [(1, 1)] [(2, 4)] [(0, 0), (2, 4)] [(1, 1)] |
请注意,运行的重复数字会被压缩。我不知道这是不是你想要的。如果没有,将
我理解你的问题。我研究了
生成范围对:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def ranges(lst): s = e = None r = [] for i in sorted(lst): if s is None: s = e = i elif i == e or i == e + 1: e = i else: r.append((s, e)) s = e = i if s is not None: r.append((s, e)) return r |
例子:
1 2 3 | >>> lst = [1, 5, 6, 7, 12, 15, 16, 17, 18, 30] >>> print repr(ranges(lst)) [(1, 1), (5, 7), (12, 12), (15, 18), (30, 30)] |
。
作为发电机:
1 2 3 4 5 6 7 8 9 10 11 12 | def gen_ranges(lst): s = e = None for i in sorted(lst): if s is None: s = e = i elif i == e or i == e + 1: e = i else: yield (s, e) s = e = i if s is not None: yield (s, e) |
号
例子:
1 2 3 | >>> lst = [1, 5, 6, 7, 12, 15, 16, 17, 18, 30] >>> print repr(','.join(['%d' % s if s == e else '%d-%d' % (s, e) for (s, e) in gen_ranges(lst)])) '1,5-7,12,15-18,30' |
号
我认为其他答案很难理解,而且可能效率低下。希望这越来越容易。
1 2 3 4 5 6 7 8 9 10 | def ranges(ints): ints = sorted(set(ints)) range_start = previous_number = ints[0] for number in ints[1:]: if number == previous_number + 1: previous_number = number else: yield range_start, previous_number range_start = previous_number = number yield range_start, previous_number |
号
把它改短:
1 | ranges=lambda l:map(lambda x:(x[0][1],x[-1][1]),map(lambda (x,y):list(y),itertools.groupby(enumerate(l),lambda (x,y):x-y))) |
。
如果在python中没有这样的特性,下面是一个实现
1 2 3 4 5 6 7 8 9 10 11 12 | p = [] last = -2 start = -1 for item in list: if item != last+1: if start != -1: p.append([start, last]) start = item last = item p.append([start, last]) |
没有内置的,或者在我所知道的任何库中。我知道,没什么帮助,但我从来没有遇到过你想要的东西。
下面是你的程序的一些想法(至少在C++中,但它可以给你一些其他的想法):
将整数集转换为范围