range_map ========= A RangeMap maps ranges to values. Keys must be hashable and comparable to all other keys (but not necessarily the same type). Each range `a:b` maps all values `a <= x < b` so it includes `a` but not `b`. Examples -------- .. code-block:: python >>> from collections_extended import RangeMap >>> from datetime import date >>> version = RangeMap() >>> version[date(2017, 10, 20): date(2017, 10, 27)] = '0.10.1' >>> version[date(2017, 10, 27): date(2018, 2, 14)] = '1.0.0' >>> version[date(2018, 2, 14):] = '1.0.1' >>> version[date(2017, 10, 24)] '0.10.1' >>> version[date(2018, 7, 1)] '1.0.1' >>> version[date(2018, 6, 30):] = '1.0.2' >>> version[date(2018, 7, 1)] '1.0.2' Creating RangeMaps ------------------ RangeMaps can be passed a mapping upon creation. Each key, value pair is interpreted as the start of a range and the mapped value. The end of the range is the next largest key in the mapping. RangeMaps can also be created from ``RangeMap.from_iterable(iterable)`` where the iterable's elements are tuples (start, stop, value). A start or stop key of None denotes an open range, ie. a start key of None is analgous to -infinity if the keys are all numbers. Quirks ------ Python 2 vs 3 ~~~~~~~~~~~~~ Slice notation is not implemented for get, set and delete in python 2 and raises a SyntaxError when used. This is because Python 2 assumes slices are integers and replaces open slices with 0 and maxint. Instead use ``RangeMap.set``, ``RangeMap.delete`` and ``RangeMap.get_range``. PyPy ~~~~ pypy (not pypy3) cannot accept non-ints in __getitem__ so RangeMap[1.5:3] doesn't work. Implementation -------------- RangeMaps are backed by lists of the keys, so it's only fast to add/remove the greatest values in the range (the end of the list). API --- .. autoclass:: collections_extended.RangeMap .. autoclass:: collections_extended.MappedRange :no-undoc-members: