2013-07-01 2 views
3

У меня есть список, какОбъединить последовательные номера в кортежи диапазона

[38, 98, 110, 111, 112, 120, 121, 898] 

Как объединить последовательные номера в пару, представляющих собой диапазон?

желаемый результат:

['38', 
'98', 
'110,112', 
'120,121', 
'898'] 
+3

почему 110 -> 112 считается последовательным? – hexparrot

+1

@hexparrot у него 110, 111, 112; Я думаю, что он означает включать все числа в «диапазон», пока не достигнет числа, которое больше не будет последовательным. – 2rs2ts

+0

ах, такой глупый недосмотр. теперь, я помню codegolf, который делает это ... brb. – hexparrot

ответ

13

Вы можете сделать это красиво с itertools.groupby, заметив, что разница между пунктами в списке, и счетчик являются постоянными, а числа являются последовательными

например

38 - 0 = 38 
98 - 1 = 97 
110 - 2 = 108 
111 - 3 = 108 
112 - 4 = 108 
120 - 5 = 115 
121 - 6 = 115 
898 - 7 = 891 

В этом примере 108-ые сгруппированы вместе, а 115 сгруппированы вместе. Теперь некоторый код

>>> from itertools import groupby, count 
>>> L = [38, 98, 110, 111, 112, 120, 121, 898] 
>>> groups = groupby(L, key=lambda item, c=count():item-next(c)) 
>>> tmp = [list(g) for k, g in groups] 

посмотреть, что у нас до сих пор

>>> tmp 
[[38], [98], [110, 111, 112], [120, 121], [898]] 

обращенного к желаемому результату

>>> [str(x[0]) if len(x) == 1 else "{},{}".format(x[0],x[-1]) for x in tmp] 
['38', '98', '110,112', '120,121', '898'] 
4

Прямой вперед решение:

def ranger(lst): 
    fr, to = lst[0], lst[0] 
    for x in lst[1:]: 
     if x == to+1: 
      to = x 
     else: 
      yield fr, to 
      fr, to = x, x 
    yield fr, to 

res = [','.join(map(str, sorted(set(x)))) for x in ranger(lst)] 
+0

выход не соответствует ему, делает дубликат одиночных чисел и пары их – Serial

+0

@ChristianCareaga исправлена. – Elazar