Package: derange
GitHub|PyPI|Issues|ChangelogDo you have a list of integers?  Do you want to know what ranges of consecutive
values the list covers?  Do you need to solve agaps and islandsproblem outside of
SQL?  Maybe you have a list of dates and need to find the longest streak of
consecutive days on which something happened.  No?  Why not?  Well, either way,
thederangemodule is here for you, ready to solve all these problems and a
couple more.Installationderangerequires Python 3.6 or higher.  Just usepipfor Python 3 (You have pip, right?) to install:python3 -m pip install derangeExamplesCondense commit years obtained fromgit logor the like intorangeobjects:>>> import derange
>>> derange.derange([2015, 2015, 2015, 2014, 2014, 2011, 2010, 2010, 2009, 2009])
[range(2009, 2012), range(2014, 2016)]If the input is already sorted, you can condense it slightly faster withderange_sorted():>>> derange.derange_sorted([2009, 2009, 2010, 2010, 2011, 2014, 2014, 2015, 2015, 2015])
[range(2009, 2012), range(2014, 2016)]Organize non-integer values into closed intervals (represented as pairs of
endpoints) withdeinterval():>>> import datetime
>>> # deinterval() requires a callable for determining when two values are "adjacent":
>>> def within_24_hours(a,b):
...     return abs(a-b) <= datetime.timedelta(hours=24)
...
>>> timestamps = [
...     datetime.datetime(2017, 11, 2, 12, 0),
...     datetime.datetime(2017, 11, 3, 11, 0),
...     datetime.datetime(2017, 11, 4, 10, 0),
...     datetime.datetime(2017, 11, 5,  9, 0),
...     datetime.datetime(2017, 11, 6,  9, 0),
...     datetime.datetime(2017, 11, 7, 10, 0),
... ]
>>> derange.deinterval(within_24_hours, timestamps)
[(datetime.datetime(2017, 11, 2, 12, 0), datetime.datetime(2017, 11, 6, 9, 0)), (datetime.datetime(2017, 11, 7, 10, 0), datetime.datetime(2017, 11, 7, 10, 0))]… which also has adeinterval_sorted()variant:>>> derange.deinterval_sorted(within_24_hours, timestamps)
[(datetime.datetime(2017, 11, 2, 12, 0), datetime.datetime(2017, 11, 6, 9, 0)), (datetime.datetime(2017, 11, 7, 10, 0), datetime.datetime(2017, 11, 7, 10, 0))]
>>> derange.deinterval_sorted(within_24_hours, reversed(timestamps))
Traceback (most recent call last):
    ...
ValueError: sequence not in ascending orderAPIderange.derange(iterable:Iterable[int])->List[range]Convert a sequence of integers to a minimal list ofrangeobjects that
together contain all of the input elements.Output is in strictly ascending order.  Input need not be in order (but see
alsoderange_sorted()).  Duplicate input values are ignored.derange.derange_sorted(iterable:Iterable[int])->List[range]Convert anon-decreasingsequence of integers to a minimal list ofrangeobjects that together contain all of the input elements.  This is faster thanderange()but only accepts sorted input.derange.deinterval(adjacent:Callable[[T,T],bool],iterable:Iterable[T],)->List[Tuple[T,T]]Convert a sequence of totally-ordered values to a minimal list of closed
intervals (represented as pairs of endpoints) that together contain all of the
input elements.  This is a generalization ofderange()for arbitrary types.Two input values will be placed in the same interval iff they are directly
adjacent or there exists a chain of adjacent input values connecting them,
where adjacency is defined by the givenadjacentcallable.adjacentwill be called with two elements ofiterableat a time to test
whether they should be placed in the same interval.  The binary relation
implied byadjacentmust be reflexive and symmetric, and for allx < y < z, ifadjacent(x, z)is true, then bothadjacent(x, y)andadjacent(y, z)must also be true.Output is in strictly ascending order.  Input need not be in order (but see
alsodeinterval_sorted()).  Duplicate input values are ignored.Note that, unlike withrangeobjects, intervals returned fromdeinterval()contain their upper bounds.derange.deinterval_sorted(adjacent:Callable[[T,T],bool],iterable:Iterable[T],)->List[Tuple[T,T]]Convert anon-decreasingsequence of totally-ordered values to a minimal list
of closed intervals that together contain all of the input elements.  This is
faster thandeinterval()but only accepts sorted input.