Определить группы непрерывных чисел в списке - PullRequest
72 голосов
/ 28 января 2010

Я бы хотел определить группы непрерывных чисел в списке, чтобы:

myfunc([2, 3, 4, 5, 12, 13, 14, 15, 16, 17, 20])

Возвращает:

[(2,5), (12,17), 20]

И мне было интересно, как лучше всего это сделать (особенно, если что-то встроено в Python).

Редактировать: Примечание. Первоначально я забыл упомянуть, что отдельные числа должны возвращаться как отдельные числа, а не как диапазоны.

Ответы [ 12 ]

0 голосов
/ 17 мая 2018

Краткое решение, которое работает без дополнительного импорта. Он принимает любые итерируемые, сортирует несортированные данные и удаляет повторяющиеся элементы:

def ranges(nums):
    nums = sorted(set(nums))
    gaps = [[s, e] for s, e in zip(nums, nums[1:]) if s+1 < e]
    edges = iter(nums[:1] + sum(gaps, []) + nums[-1:])
    return list(zip(edges, edges))

Пример:

>>> ranges([2, 3, 4, 7, 8, 9, 15])
[(2, 4), (7, 9), (15, 15)]

>>> ranges([-1, 0, 1, 2, 3, 12, 13, 15, 100])
[(-1, 3), (12, 13), (15, 15), (100, 100)]

>>> ranges(range(100))
[(0, 99)]

>>> ranges([0])
[(0, 0)]

>>> ranges([])
[]

Это то же самое, что и решение @ dansalmo , которое мне показалось удивительным, хотя и немного сложным для чтения и применения (поскольку оно не дано как функция).

Обратите внимание, что его можно легко изменить, чтобы он выплевывал "традиционные" открытые диапазоны [start, end), например, изменение оператора возврата:

    return [(s, e+1) for s, e in zip(edges, edges)]

Я скопировал этот ответ из другого вопроса , который был помечен как дубликат этого с целью облегчить его поиск (после того, как я только что снова искал эту тему, найдя только вопрос здесь сначала и не удовлетворены ответами).

0 голосов
/ 01 мая 2018

Использование списков numpy +:
С помощью функции numpy diff могут быть определены последовательные входные векторные записи, что их разность не равна единице. Начало и конец входного вектора необходимо учитывать.

import numpy as np
data = np.array([2, 3, 4, 5, 12, 13, 14, 15, 16, 17, 20])

d = [i for i, df in enumerate(np.diff(data)) if df!= 1] 
d = np.hstack([-1, d, len(data)-1])  # add first and last elements 
d = np.vstack([d[:-1]+1, d[1:]]).T

print(data[d])

Выход:

 [[ 2  5]   
  [12 17]   
  [20 20]]

Примечание. Запрос о том, что отдельные номера должны обрабатываться по-разному (возвращаются как отдельные, а не диапазоны), был опущен. Это может быть достигнуто путем дальнейшей обработки результатов. Обычно это усложняет ситуацию, не принося никакой пользы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...