0
# Range Mappings
1
2
RangeMaps provide efficient mappings from continuous ranges to values using interval-based storage. They support slice notation, range operations, and are ideal for time series data, version ranges, and any scenario requiring interval-to-value mappings.
3
4
## Capabilities
5
6
### RangeMap Construction
7
8
Create range mappings from various input formats with optional default values.
9
10
```python { .api }
11
class RangeMap:
12
def __init__(self, iterable=None, default_value=NOT_SET):
13
"""Create a RangeMap.
14
15
Args:
16
iterable: Mapping (start -> value) or iterable of (start, stop, value) tuples
17
default_value: Default value for unmapped ranges
18
"""
19
20
@classmethod
21
def from_mapping(cls, mapping):
22
"""Create RangeMap from mapping of range starts to values.
23
24
Args:
25
mapping: Dict mapping start points to values
26
27
Returns:
28
RangeMap: New range map
29
"""
30
31
@classmethod
32
def from_iterable(cls, iterable):
33
"""Create RangeMap from iterable of (start, stop, value) tuples.
34
35
Args:
36
iterable: Iterable of (start, stop, value) tuples
37
38
Returns:
39
RangeMap: New range map
40
"""
41
```
42
43
Usage examples:
44
```python
45
from collections_extended import RangeMap
46
from datetime import date
47
48
# Empty range map
49
rm = RangeMap()
50
51
# With default value for unmapped ranges
52
rm_default = RangeMap(default_value='unknown')
53
54
# From mapping of start points
55
starts = {0: 'low', 10: 'medium', 20: 'high'}
56
rm_starts = RangeMap.from_mapping(starts)
57
58
# From tuples of (start, stop, value)
59
ranges = [(0, 5, 'first'), (5, 10, 'second'), (10, 15, 'third')]
60
rm_ranges = RangeMap.from_iterable(ranges)
61
```
62
63
### Range Setting and Access
64
65
Set and retrieve values for specific ranges using slice notation or method calls.
66
67
```python { .api }
68
def set(self, value, start=None, stop=None):
69
"""Set range from start to stop to value.
70
71
Args:
72
value: Value to assign to the range
73
start: Start of range (inclusive, None for unbounded left)
74
stop: End of range (exclusive, None for unbounded right)
75
"""
76
77
def get(self, key, restval=None):
78
"""Get value for a specific key.
79
80
Args:
81
key: Point to look up
82
restval: Value to return if key not mapped
83
84
Returns:
85
Any: Value at key or restval if unmapped
86
"""
87
88
def __getitem__(self, key):
89
"""Get value for key or range slice.
90
91
Args:
92
key: Point to look up or slice for sub-range
93
94
Returns:
95
Any: Value at key or RangeMap for slice
96
97
Raises:
98
KeyError: If key not mapped and no default value
99
"""
100
101
def __setitem__(self, key, value):
102
"""Set range using slice notation.
103
104
Args:
105
key: slice object defining the range
106
value: Value to assign to the range
107
"""
108
```
109
110
Usage examples:
111
```python
112
rm = RangeMap()
113
114
# Set ranges using method calls
115
rm.set('morning', start=6, stop=12)
116
rm.set('afternoon', start=12, stop=18)
117
rm.set('evening', start=18, stop=22)
118
119
# Set ranges using slice notation
120
rm[0:6] = 'night'
121
rm[22:24] = 'late_night'
122
123
# Access specific points
124
print(rm[8]) # 'morning'
125
print(rm[15]) # 'afternoon'
126
print(rm.get(25, 'unmapped')) # 'unmapped'
127
128
# Access sub-ranges
129
sub_range = rm[10:20] # RangeMap with overlapping ranges
130
```
131
132
### Range Queries and Iteration
133
134
Query range information and iterate over mapped intervals.
135
136
```python { .api }
137
def ranges(self, start=None, stop=None):
138
"""Generate MappedRange objects for ranges in the specified interval.
139
140
Args:
141
start: Start of query interval (None for unbounded)
142
stop: End of query interval (None for unbounded)
143
144
Yields:
145
MappedRange: Range objects with start, stop, and value
146
"""
147
148
def get_range(self, start=None, stop=None):
149
"""Return a RangeMap covering the specified range.
150
151
Args:
152
start: Start of range to extract
153
stop: End of range to extract
154
155
Returns:
156
RangeMap: New RangeMap covering the specified range
157
"""
158
159
def __contains__(self, key):
160
"""Check if key is mapped to a value.
161
162
Args:
163
key: Point to check
164
165
Returns:
166
bool: True if key is mapped
167
"""
168
169
def __iter__(self):
170
"""Iterate over range start points that have mappings."""
171
172
def __len__(self):
173
"""Return number of mapped ranges.
174
175
Returns:
176
int: Count of ranges with values
177
"""
178
179
def __bool__(self):
180
"""Return True if any ranges are mapped.
181
182
Returns:
183
bool: True if RangeMap contains mappings
184
"""
185
```
186
187
Usage examples:
188
```python
189
rm = RangeMap()
190
rm[0:10] = 'first'
191
rm[10:20] = 'second'
192
rm[30:40] = 'third'
193
194
# Iterate over all ranges
195
for range_obj in rm.ranges():
196
print(f"[{range_obj.start}:{range_obj.stop}) -> {range_obj.value}")
197
198
# Query specific interval
199
for range_obj in rm.ranges(5, 35):
200
print(f"Overlaps query: [{range_obj.start}:{range_obj.stop}) -> {range_obj.value}")
201
202
# Extract sub-range
203
partial = rm.get_range(5, 25) # Includes parts of 'first' and 'second'
204
205
# Basic queries
206
print(5 in rm) # True
207
print(25 in rm) # False
208
print(len(rm)) # 3
209
print(bool(rm)) # True
210
```
211
212
### Range Modification
213
214
Modify, delete, and clear ranges efficiently.
215
216
```python { .api }
217
def delete(self, start=None, stop=None):
218
"""Delete the specified range.
219
220
Args:
221
start: Start of range to delete (None for unbounded)
222
stop: End of range to delete (None for unbounded)
223
224
Raises:
225
KeyError: If any part of the range is not mapped
226
"""
227
228
def empty(self, start=None, stop=None):
229
"""Empty the specified range (like delete but doesn't raise errors).
230
231
Args:
232
start: Start of range to empty (None for unbounded)
233
stop: End of range to empty (None for unbounded)
234
"""
235
236
def clear(self):
237
"""Remove all mappings from the RangeMap."""
238
239
def __delitem__(self, key):
240
"""Delete range using slice notation.
241
242
Args:
243
key: slice object defining range to delete
244
"""
245
```
246
247
Usage examples:
248
```python
249
rm = RangeMap()
250
rm[0:50] = 'full_range'
251
rm[10:20] = 'middle'
252
rm[30:40] = 'end'
253
254
# Delete specific range
255
del rm[15:25] # Removes part of 'middle' and gap
256
257
# Empty range (no error if unmapped)
258
rm.empty(45, 60) # Removes part of range, no error for unmapped part
259
260
# Delete with error checking
261
try:
262
rm.delete(100, 110) # KeyError - range not mapped
263
except KeyError:
264
print("Range not fully mapped")
265
266
# Clear everything
267
rm.clear()
268
print(len(rm)) # 0
269
```
270
271
### Boundary Properties
272
273
Access information about range boundaries and extents.
274
275
```python { .api }
276
@property
277
def start(self):
278
"""Get the start of the first mapped range.
279
280
Returns:
281
Any: Start point of first range or None if empty/unbounded
282
"""
283
284
@property
285
def end(self):
286
"""Get the end of the last mapped range.
287
288
Returns:
289
Any: End point of last range or None if empty/unbounded
290
"""
291
```
292
293
Usage examples:
294
```python
295
rm = RangeMap()
296
rm[10:20] = 'first'
297
rm[30:40] = 'second'
298
299
print(rm.start) # 10
300
print(rm.end) # 40
301
302
# Unbounded ranges
303
rm[:5] = 'prefix' # Unbounded left
304
rm[50:] = 'suffix' # Unbounded right
305
306
print(rm.start) # None (unbounded left)
307
print(rm.end) # None (unbounded right)
308
```
309
310
### MappedRange Objects
311
312
Represent individual range mappings with start, stop, and value information.
313
314
```python { .api }
315
class MappedRange:
316
def __init__(self, start, stop, value):
317
"""Create a mapped range.
318
319
Args:
320
start: Range start (inclusive)
321
stop: Range end (exclusive)
322
value: Associated value
323
"""
324
325
start: Any # Range start point (inclusive)
326
stop: Any # Range end point (exclusive)
327
value: Any # Associated value
328
329
def __iter__(self):
330
"""Allow unpacking: start, stop, value = mapped_range"""
331
332
def __eq__(self, other):
333
"""Check equality with another MappedRange."""
334
335
def __str__(self):
336
"""String representation: [start, stop) -> value"""
337
338
def __repr__(self):
339
"""Detailed representation for debugging."""
340
```
341
342
Usage examples:
343
```python
344
from collections_extended import MappedRange
345
346
# Create manually
347
mr = MappedRange(0, 10, 'first_range')
348
print(mr) # [0, 10) -> first_range
349
350
# Unpack from ranges() iteration
351
rm = RangeMap()
352
rm[0:10] = 'test'
353
for start, stop, value in rm.ranges():
354
print(f"Range from {start} to {stop}: {value}")
355
356
# Access attributes
357
for range_obj in rm.ranges():
358
print(f"Start: {range_obj.start}")
359
print(f"Stop: {range_obj.stop}")
360
print(f"Value: {range_obj.value}")
361
```
362
363
### View Operations
364
365
Access keys, values, and items through view objects.
366
367
```python { .api }
368
def keys(self):
369
"""Return view of range start keys.
370
371
Returns:
372
RangeMapKeysView: View iterating over range start points
373
"""
374
375
def values(self):
376
"""Return view of range values.
377
378
Returns:
379
RangeMapValuesView: View iterating over unique values
380
"""
381
382
def items(self):
383
"""Return view of (start, value) pairs.
384
385
Returns:
386
RangeMapItemsView: View iterating over start-value pairs
387
"""
388
```
389
390
Usage examples:
391
```python
392
rm = RangeMap()
393
rm[0:10] = 'first'
394
rm[10:20] = 'second'
395
rm[20:30] = 'first' # Same value as first range
396
397
print(list(rm.keys())) # [0, 10, 20]
398
print(list(rm.values())) # ['first', 'second'] - unique values only
399
print(list(rm.items())) # [(0, 'first'), (10, 'second'), (20, 'first')]
400
401
# Views support membership testing
402
print(15 in rm.keys()) # False (15 is not a start point)
403
print('first' in rm.values()) # True
404
print((10, 'second') in rm.items()) # True
405
```
406
407
### Advanced Usage Patterns
408
409
Common patterns for effective RangeMap usage.
410
411
```python
412
from datetime import date, timedelta
413
414
# Version ranges for software releases
415
versions = RangeMap()
416
versions[date(2020, 1, 1):date(2020, 6, 1)] = '1.0'
417
versions[date(2020, 6, 1):date(2021, 1, 1)] = '1.1'
418
versions[date(2021, 1, 1):] = '2.0'
419
420
current_version = versions[date.today()]
421
422
# Price tiers based on quantity
423
pricing = RangeMap(default_value=0.50) # Default unit price
424
pricing[100:500] = 0.45 # Volume discount
425
pricing[500:1000] = 0.40 # Larger volume discount
426
pricing[1000:] = 0.35 # Highest volume discount
427
428
unit_price = pricing[quantity]
429
430
# Time-based scheduling
431
schedule = RangeMap()
432
schedule[6:9] = 'morning_shift'
433
schedule[9:17] = 'day_shift'
434
schedule[17:22] = 'evening_shift'
435
schedule[22:6] = 'night_shift' # Wraps around (if using 24-hour periods)
436
437
current_shift = schedule.get(current_hour, 'off_duty')
438
439
# Overlapping range updates
440
temp_map = RangeMap()
441
temp_map[0:100] = 'baseline'
442
temp_map[20:30] = 'override' # Splits baseline into [0:20) and [30:100)
443
444
# Merging adjacent ranges with same value
445
data = RangeMap()
446
data[0:10] = 'same'
447
data[10:20] = 'same' # Automatically merged into [0:20) = 'same'
448
```