0
# Bijections and One-to-One Mappings
1
2
Bijections are one-to-one mappings that maintain both forward and inverse relationships automatically. They enforce uniqueness in both keys and values, providing efficient bidirectional lookups and automatic inverse maintenance.
3
4
## Capabilities
5
6
### Bijection Construction
7
8
Create one-to-one mappings from various input formats.
9
10
```python { .api }
11
class bijection:
12
def __init__(self, iterable=None, **kwargs):
13
"""Create a bijection from an iterable or keyword arguments.
14
15
Args:
16
iterable: Mapping or iterable of (key, value) pairs
17
**kwargs: Additional key-value pairs
18
"""
19
```
20
21
Usage examples:
22
```python
23
from collections_extended import bijection
24
25
# Create from dictionary
26
b1 = bijection({'a': 1, 'b': 2, 'c': 3})
27
28
# Create from iterable of pairs
29
b2 = bijection([('x', 10), ('y', 20), ('z', 30)])
30
31
# Create with keyword arguments
32
b3 = bijection(a=1, b=2, c=3)
33
34
# Create from another bijection
35
b4 = bijection(b1)
36
```
37
38
### Inverse Relationship
39
40
Access the inverse mapping automatically maintained for bidirectional lookups.
41
42
```python { .api }
43
@property
44
def inverse(self):
45
"""Return the inverse bijection.
46
47
The inverse maps values to keys automatically. Changes to either
48
the bijection or its inverse are reflected in both.
49
50
Returns:
51
bijection: Inverse mapping (values -> keys)
52
"""
53
```
54
55
Usage examples:
56
```python
57
b = bijection({'alice': 1, 'bob': 2, 'charlie': 3})
58
59
# Forward lookup
60
print(b['alice']) # 1
61
62
# Inverse lookup
63
print(b.inverse[2]) # 'bob'
64
65
# Both directions work
66
print(b.inverse['alice']) # KeyError - 'alice' is a key, not a value
67
print(b.inverse[1]) # 'alice'
68
```
69
70
### Mapping Operations
71
72
Standard mapping operations with bijection uniqueness constraints.
73
74
```python { .api }
75
def __getitem__(self, key):
76
"""Get value for key.
77
78
Args:
79
key: Key to look up
80
81
Returns:
82
Any: Value associated with key
83
84
Raises:
85
KeyError: If key not found
86
"""
87
88
def __setitem__(self, key, value):
89
"""Set key to value, maintaining bijection property.
90
91
If key already exists, its old value is removed from inverse.
92
If value already exists, its old key is removed.
93
94
Args:
95
key: Key to set
96
value: Value to associate with key
97
"""
98
99
def __delitem__(self, key):
100
"""Delete key and its value from both directions.
101
102
Args:
103
key: Key to delete
104
105
Raises:
106
KeyError: If key not found
107
"""
108
109
def __contains__(self, key):
110
"""Check if key is in the bijection.
111
112
Args:
113
key: Key to check
114
115
Returns:
116
bool: True if key exists
117
"""
118
119
def __len__(self):
120
"""Return number of key-value pairs.
121
122
Returns:
123
int: Number of mappings
124
"""
125
126
def __iter__(self):
127
"""Iterate over keys."""
128
```
129
130
Usage examples:
131
```python
132
b = bijection({'a': 1, 'b': 2})
133
134
# Setting overwrites and maintains uniqueness
135
b['c'] = 3 # bijection({'a': 1, 'b': 2, 'c': 3})
136
b['a'] = 4 # bijection({'a': 4, 'b': 2, 'c': 3}) - old value 1 removed
137
b['d'] = 2 # bijection({'a': 4, 'd': 2, 'c': 3}) - old key 'b' removed
138
139
# Standard mapping operations
140
print('a' in b) # True
141
print(len(b)) # 3
142
del b['d'] # bijection({'a': 4, 'c': 3})
143
```
144
145
### Inverse Operations
146
147
Operations can be performed on either direction of the bijection.
148
149
```python { .api }
150
# All mapping operations work on inverse too
151
b.inverse[value] = key # Set inverse mapping
152
del b.inverse[value] # Delete by value
153
key = b.inverse[value] # Get key for value
154
value in b.inverse # Check if value exists
155
```
156
157
Usage examples:
158
```python
159
b = bijection({'alice': 1, 'bob': 2})
160
161
# Modify through inverse
162
b.inverse[3] = 'charlie' # bijection({'alice': 1, 'bob': 2, 'charlie': 3})
163
b.inverse[1] = 'alice_updated' # bijection({'alice_updated': 1, 'bob': 2, 'charlie': 3})
164
165
# Delete through inverse
166
del b.inverse[2] # bijection({'alice_updated': 1, 'charlie': 3})
167
168
# Query through inverse
169
print('alice_updated' in b.inverse.values()) # True - but use b.inverse[1] instead
170
```
171
172
### View Operations
173
174
Access keys, values, and items like a standard mapping.
175
176
```python { .api }
177
def keys(self):
178
"""Return view of keys.
179
180
Returns:
181
dict_keys: View of bijection keys
182
"""
183
184
def values(self):
185
"""Return view of values.
186
187
Returns:
188
dict_keys: View of bijection values (same as inverse.keys())
189
"""
190
191
def items(self):
192
"""Return view of (key, value) pairs.
193
194
Returns:
195
dict_items: View of bijection items
196
"""
197
```
198
199
Usage examples:
200
```python
201
b = bijection({'a': 1, 'b': 2, 'c': 3})
202
203
print(list(b.keys())) # ['a', 'b', 'c']
204
print(list(b.values())) # [1, 2, 3]
205
print(list(b.items())) # [('a', 1), ('b', 2), ('c', 3)]
206
207
# Values are same as inverse keys
208
print(list(b.values()) == list(b.inverse.keys())) # True
209
```
210
211
### Bijection Maintenance
212
213
Operations for copying, clearing, and maintaining bijection state.
214
215
```python { .api }
216
def copy(self):
217
"""Return a shallow copy of the bijection.
218
219
Returns:
220
bijection: New bijection with same mappings
221
"""
222
223
def clear(self):
224
"""Remove all mappings from the bijection."""
225
226
def __eq__(self, other):
227
"""Check equality with another bijection.
228
229
Args:
230
other: Object to compare with
231
232
Returns:
233
bool: True if other is bijection with same mappings
234
"""
235
```
236
237
Usage examples:
238
```python
239
b1 = bijection({'a': 1, 'b': 2})
240
b2 = b1.copy()
241
242
print(b1 == b2) # True
243
print(b1 is b2) # False
244
245
b1.clear()
246
print(len(b1)) # 0
247
print(len(b2)) # 2 - copy unaffected
248
```
249
250
### Advanced Usage Patterns
251
252
Common patterns for working with bijections effectively.
253
254
```python
255
# Swapping keys and values
256
original = bijection({'name': 'alice', 'age': 25})
257
swapped = bijection(original.inverse) # {alice': 'name', 25: 'age'}
258
259
# Building bidirectional mappings incrementally
260
mapping = bijection()
261
for i, name in enumerate(['alice', 'bob', 'charlie']):
262
mapping[name] = i
263
# Now mapping['alice'] = 0 and mapping.inverse[0] = 'alice'
264
265
# Safe updates preserving bijection property
266
b = bijection({'a': 1, 'b': 2})
267
if 'c' not in b and 3 not in b.inverse:
268
b['c'] = 3 # Safe to add
269
270
# Checking for conflicts before assignment
271
key, value = 'new_key', 'new_value'
272
if key in b:
273
print(f"Key {key} already maps to {b[key]}")
274
if value in b.inverse:
275
print(f"Value {value} already mapped from {b.inverse[value]}")
276
```
277
278
### Error Handling
279
280
Understanding bijection constraint violations and common error scenarios.
281
282
```python
283
# KeyError when accessing non-existent keys/values
284
b = bijection({'a': 1})
285
try:
286
value = b['missing']
287
except KeyError:
288
print("Key not found")
289
290
try:
291
key = b.inverse[999]
292
except KeyError:
293
print("Value not found")
294
295
# Bijection automatically handles overwrites
296
b = bijection({'a': 1, 'b': 2})
297
b['a'] = 2 # This removes the old 'b': 2 mapping automatically
298
print(b) # bijection({'a': 2})
299
```