-
-
Notifications
You must be signed in to change notification settings - Fork 50.4k
Expand file tree
/
Copy pathcoordinate_compression.py
More file actions
134 lines (109 loc) · 3.78 KB
/
coordinate_compression.py
File metadata and controls
134 lines (109 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""
Assumption:
- The values to compress are assumed to be comparable,
values can be sorted and compared with '<' and '>' operators.
"""
class CoordinateCompressor:
"""
A class for coordinate compression.
This class allows you to compress and decompress a list of values.
Mapping:
In addition to compression and decompression, this class maintains a mapping
between original values and their compressed counterparts using two data
structures: a dictionary `coordinate_map` and a list `reverse_map`:
- `coordinate_map`: A dictionary that maps original values to compressed
coordinates.
- `reverse_map`: A list used for reverse mapping, where each index corresponds
to a compressed coordinate, and the value at that index is the original value.
Example of mapping:
Original: 10, Compressed: 0
Original: 52, Compressed: 1
Original: 83, Compressed: 2
Original: 100, Compressed: 3
"""
def __init__(self, arr: list[int | float | str]) -> None:
"""
Initialize the CoordinateCompressor with a list.
Args:
arr: The list of values to be compressed.
>>> arr = [100, 10, 52, 83]
>>> cc = CoordinateCompressor(arr)
>>> cc.compress(100)
3
>>> cc.compress(52)
1
>>> cc.decompress(1)
52
"""
self.coordinate_map: dict[int | float | str, int] = {}
self.reverse_map: list[int | float | str] = [-1] * len(arr)
self.arr = sorted(arr)
self.n = len(arr)
self.compress_coordinates()
def compress_coordinates(self) -> None:
"""
Compress the coordinates in the input list.
>>> arr = [100, 10, 52, 83]
>>> cc = CoordinateCompressor(arr)
>>> cc.coordinate_map[83]
2
>>> cc.reverse_map[2]
83
"""
key = 0
for val in self.arr:
if val not in self.coordinate_map:
self.coordinate_map[val] = key
self.reverse_map[key] = val
key += 1
def compress(self, original: float | str) -> int:
"""
Compress a single value.
Args:
original: The value to compress.
Returns:
The compressed integer.
Raises:
ValueError if the value is not in the original list.
>>> arr = [100, 10, 52, 83]
>>> cc = CoordinateCompressor(arr)
>>> cc.compress(100)
3
>>> cc.compress(7)
Traceback (most recent call last):
...
ValueError: Value 7 not found in coordinate map.
"""
if original not in self.coordinate_map:
raise ValueError(f"Value {original} not found in coordinate map.")
return self.coordinate_map[original]
def decompress(self, num: int) -> int | float | str:
"""
Decompress a single integer.
Args:
num: The compressed integer to decompress.
Returns:
The original value.
Raises:
ValueError if the compressed coordinate is out of range.
>>> arr = [100, 10, 52, 83]
>>> cc = CoordinateCompressor(arr)
>>> cc.decompress(0)
10
>>> cc.decompress(5)
Traceback (most recent call last):
...
ValueError: Index 5 out of range.
"""
if 0 <= num < len(self.reverse_map):
return self.reverse_map[num]
raise ValueError(f"Index {num} out of range.")
if __name__ == "__main__":
from doctest import testmod
testmod()
arr: list[int | float | str] = [100, 10, 52, 83]
cc = CoordinateCompressor(arr)
for original in arr:
compressed = cc.compress(original)
decompressed = cc.decompress(compressed)
print(f"Original: {decompressed}, Compressed: {compressed}")