I'm currently working on an api where they send me a str range in this format: "1-5,10-25,27-30" and i need add or remove number conserving the format.
if they send me "1-5,10-25,27-30" and I remove "15" the result must be "1-5,10-14,16-25,27-30" and if they send me "1-5,10-25,27-30" and i add "26" the result must be "1-5,10-30"
i've been trying converting the entire range into a list of numbers, delete the target and converting it again but it's very slow doing in this way becuase they send 8-digits numbers so iter then it's not the best way
how can i do this? is a library for work with this format?
thanks!
intspan deals with ranges of integers and operations on them
>>> from intspan import intspan
>>> s = "1-5,10-25,27-30"
>>> span = intspan(s)
>>> str(span)
'1-5,10-25,27-30'
>>> span.add(26)
>>> str(span)
'1-5,10-30'
>>> span.discard(15)
>>> str(span)
'1-5,10-14,16-30'
This represents ranges by lists of two-element lists. Two-element lists are used as this allows ranges boundaries to be mutated.
# -*- coding: utf-8 -*-
"""
https://stackoverflow.com/questions/64466231/pythonic-way-to-operate-comma-separated-list-of-ranges-1-5-10-25-27-30
Created on Wed Oct 21 16:29:39 2020
@author: Paddy3118
"""
def to_ranges(txt):
return [[int(x) for x in r.strip().split('-')]
for r in txt.strip().split(',')]
def remove_int(rem, ranges):
for i, r in enumerate(ranges):
if r[0] <= rem <= r[1]:
if r[0] == rem: # range min
if r[1] > rem:
r[0] += 1
else:
del ranges[i]
elif r[1] == rem: # range max
if r[0] < rem:
r[1] -= 1
else:
del ranges[i]
else: # inside, range extremes.
r[1], splitrange = rem - 1, [rem + 1, r[1]]
ranges.insert(i + 1, splitrange)
break
if r[0] > rem: # Not in sorted list
break
return ranges
def add_int(add, ranges):
for i, r in enumerate(ranges):
if r[0] <= add <= r[1]: # already included
break
elif r[0] - 1 == add: # rough extend to here
r[0] = add
break
elif r[1] + 1 == add: # rough extend to here
r[1] = add
break
elif r[0] > add: # rough insert here
ranges.insert(i, [add, add])
break
else:
ranges.append([add, add])
return ranges
return consolidate(ranges)
def consolidate(ranges):
"Combine overlapping ranges"
for this, that in zip(ranges, ranges[1:]):
if this[1] + 1 >= that[0]: # Ranges interract
if this[1] >= that[1]: # this covers that
this[:], that[:] = [], this
else: # that extends this
this[:], that[:] = [], [this[0], that[1]]
ranges[:] = [r for r in ranges if r]
return ranges
sent = "1-5,10-25,27-30"
ll = to_ranges(sent)
assert ll == sorted(ll)
Sample calculations
In [68]: ll
Out[68]: [[1, 5], [10, 25], [27, 30]]
In [69]: add_int(26, ll)
Out[69]: [[1, 5], [10, 30]]
In [70]: add_int(9, ll)
Out[70]: [[1, 5], [9, 30]]
In [71]: add_int(7, ll)
Out[71]: [[1, 5], [7, 7], [9, 30]]
In [72]: remove_int(26, ll)
Out[72]: [[1, 5], [7, 7], [9, 25], [27, 30]]
In [73]: remove_int(9, ll)
Out[73]: [[1, 5], [7, 7], [10, 25], [27, 30]]
In [74]: remove_int(7, ll)
Out[74]: [[1, 5], [10, 25], [27, 30]]
In [75]:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With