Свернуть последовательности чисел в диапазоны - PullRequest
0 голосов
/ 12 сентября 2018

Сегодня я прошу помощи с написанным мной скриптом Python; Я использую модуль CSV для анализа большого документа с примерно 1100 строками, и из каждой строки он извлекает Case_ID, уникальный номер, которого нет ни у одной другой строки. Например:

['10215', '10216', '10277', '10278', '10279', '10280', '10281', '10282', '10292', '10293',
'10295', '10296', '10297', '10298', '10299', '10300', '10301', '10302', '10303', '10304',
'10305', '10306', '10307', '10308', '10309', '10310', '10311', '10312', '10313', '10314',
'10315', '10316', '10317', '10318', '10319', '10320', '10321', '10322', '10323', '10324',
'10325', '10326', '10344', '10399', '10400', '10401', '10402', '10403', '10404', '10405',
'10406', '10415', '10416', '10417', '10418', '10430', '10448', '10492', '10493', '10494',
'10495', '10574', '10575', '10576', '10577', '10578', '10579', '10580', '10581', '10582',
'10583', '10584', '10585', '10586', '10587', '10588', '10589', '10590', '10591', '10592',
'10593', '10594', '10595', '10596', '10597', '10598', '10599', '10600', '10601', '10602',
'10603', '10604', '10605', '10606', '10607', '10608', '10609', '10610', '10611', '10612',
'10613', '10614', '10615', '10616', '10617', '10618', '10619', '10620', '10621', '10622',
'10623', '10624', '10625', '10626', '10627', '10628', '10629', '10630', '10631', '10632',
'10633', '10634', '10635', '10636', '10637', '10638', '10639', '10640', '10641', '10642',
'10643', '10644', '10645', '10646', '10647', '10648', '10649', '10650', '10651', '10652',
'10653', '10654', '10655', '10656', '10657', '10658', '10659', '10707', '10708', '10709',
'10710', '10792', '10793', '10794', '10795', '10908', '10936', '10937', '10938', '10939',
'11108', '11109', '11110', '11111', '11112', '11113', '11114', '11115', '11116', '11117',
'11118', '11119', '11120', '11121', '11122', '11123', '11124', '11125', '11126', '11127',
'11128', '11129', '11130', '11131', '11132', '11133', '11134', '11135', '11136', '11137',
'11138', '11139', '11140', '11141', '11142', '11143', '11144', '11145', '11146', '11147',
'11148', '11149', '11150', '11151', '11152', '11153', '11154', '11155', '11194', '11195',
'11196', '11197', '11198', '11199', '11200', '11201', '11202', '11203', '11204', '11205',
'11206', '11207', '11208', '11209', '11210', '11211', '11212', '11213', '11214', '11215',
'11216', '11217', '11218', '11219', '11220', '11221', '11222', '11223', '11224', '11225',
'11226', '11227', '11228', '11229', '11230', '11231', '11232', '11233', '11234', '11235',
'10101', '10102', '10800', '11236']

Как вы можете видеть, этот список довольно придирчив, поэтому я хотел бы включить небольшую небольшую функцию в мой скрипт, которая может уменьшить все последовательные диапазоны вплоть до переносных элементов типа дефис, например, 10,277 - 10,282 ,

Спасибо всем за любую помощь! Хорошего дня.

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Вы можете просто использовать простой цикл со следующей логикой:

  1. Создать список для хранения диапазонов (ranges).
  2. Перебирать значения в вашем списке (l)
  3. Если ranges пусто, добавить список с первым значением в l к ranges
  4. В противном случае, если разница между текущим и предыдущим значением равна 1, добавьте текущее значение в последний список в ranges
  5. В противном случае добавить список с текущим значением в ranges

Код:

l = ['10215', '10216', '10277', '10278', '10279', '10280', ...]

ranges = []
for x in l:
    if not ranges:
        ranges.append([x])
    elif int(x)-prev_x == 1:
        ranges[-1].append(x)
    else:
        ranges.append([x])
    prev_x = int(x)

Теперь вы можете вычислить свои окончательные диапазоны, объединив первый и последний элемент каждого списка в ranges (если есть хотя бы 2 элемента).

final_ranges = ["-".join([r[0], r[-1]] if len(r) > 1 else r) for r in ranges]
print(final_ranges)
#['10215-10216',
# '10277-10282',
# '10292-10293',
# '10295-10326',
# '10344',
# '10399-10406',
# '10415-10418',
# '10430',
# '10448',
# '10492-10495',
# '10574-10659',
# '10707-10710',
# '10792-10795',
# '10908',
# '10936-10939',
# '11108-11155',
# '11194-11235',
# '10101-10102',
# '10800',
# '11236']

Это также предполагает, что ваши данные отсортированы. Вы можете упростить код для объединения пунктов 3 и 5.


Для чисто образовательных целей (это гораздо более неэффективно, чем в приведенном выше цикле), здесь то же самое, используя map и reduce:

from functools import reduce

def myreducer(ranges, x):
    if not ranges:
        return [[x]]
    elif (int(x) - int(ranges[-1][-1]) == 1):
        return ranges[:-1] + [ranges[-1]+[x]] 
    else:
        return ranges + [[x]]

final_ranges = map(
    lambda r: "-".join([r[0], r[-1]] if len(r) > 1 else r),
    reduce(myreducer, l, [])
)
0 голосов
/ 12 сентября 2018

выполнимо.Давайте посмотрим, можно ли это сделать с пандами.

import pandas as pd

data = ['10215', '10216', '10277', ...]
# Load data as series.
s = pd.Series(data)
# Find all consecutive rows with a difference of one 
# and bin them into groups using `cumsum`. 
v = s.astype(int).diff().bfill().ne(1).cumsum() 
# Use `groupby` and `apply` to condense the consecutive numbers into ranges.
# This is only done if the group size is >1.
ranges = (
    s.groupby(v).apply(
        lambda x: '-'.join(x.values[[0, -1]]) if len(x) > 1 else x.item()).tolist())

print (ranges)
['10215-10216',
 '10277-10282',
 '10292-10293',
 '10295-10326',
 '10344',
 '10399-10406',
 '10415-10418',
 '10430',
 '10448',
 '10492-10495',
 '10574-10659',
 '10707-10710',
 '10792-10795',
 '10908',
 '10936-10939',
 '11108-11155',
 '11194-11235',
 '10101-10102',
 '10800',
 '11236']

Ваши данные должны быть отсортированы, чтобы это работало.

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