Extra Python Collections - bags (multisets) and setlists (ordered sets)
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
Create one-to-one mappings from various input formats.
class bijection:
def __init__(self, iterable=None, **kwargs):
"""Create a bijection from an iterable or keyword arguments.
Args:
iterable: Mapping or iterable of (key, value) pairs
**kwargs: Additional key-value pairs
"""Usage examples:
from collections_extended import bijection
# Create from dictionary
b1 = bijection({'a': 1, 'b': 2, 'c': 3})
# Create from iterable of pairs
b2 = bijection([('x', 10), ('y', 20), ('z', 30)])
# Create with keyword arguments
b3 = bijection(a=1, b=2, c=3)
# Create from another bijection
b4 = bijection(b1)Access the inverse mapping automatically maintained for bidirectional lookups.
@property
def inverse(self):
"""Return the inverse bijection.
The inverse maps values to keys automatically. Changes to either
the bijection or its inverse are reflected in both.
Returns:
bijection: Inverse mapping (values -> keys)
"""Usage examples:
b = bijection({'alice': 1, 'bob': 2, 'charlie': 3})
# Forward lookup
print(b['alice']) # 1
# Inverse lookup
print(b.inverse[2]) # 'bob'
# Both directions work
print(b.inverse['alice']) # KeyError - 'alice' is a key, not a value
print(b.inverse[1]) # 'alice'Standard mapping operations with bijection uniqueness constraints.
def __getitem__(self, key):
"""Get value for key.
Args:
key: Key to look up
Returns:
Any: Value associated with key
Raises:
KeyError: If key not found
"""
def __setitem__(self, key, value):
"""Set key to value, maintaining bijection property.
If key already exists, its old value is removed from inverse.
If value already exists, its old key is removed.
Args:
key: Key to set
value: Value to associate with key
"""
def __delitem__(self, key):
"""Delete key and its value from both directions.
Args:
key: Key to delete
Raises:
KeyError: If key not found
"""
def __contains__(self, key):
"""Check if key is in the bijection.
Args:
key: Key to check
Returns:
bool: True if key exists
"""
def __len__(self):
"""Return number of key-value pairs.
Returns:
int: Number of mappings
"""
def __iter__(self):
"""Iterate over keys."""Usage examples:
b = bijection({'a': 1, 'b': 2})
# Setting overwrites and maintains uniqueness
b['c'] = 3 # bijection({'a': 1, 'b': 2, 'c': 3})
b['a'] = 4 # bijection({'a': 4, 'b': 2, 'c': 3}) - old value 1 removed
b['d'] = 2 # bijection({'a': 4, 'd': 2, 'c': 3}) - old key 'b' removed
# Standard mapping operations
print('a' in b) # True
print(len(b)) # 3
del b['d'] # bijection({'a': 4, 'c': 3})Operations can be performed on either direction of the bijection.
# All mapping operations work on inverse too
b.inverse[value] = key # Set inverse mapping
del b.inverse[value] # Delete by value
key = b.inverse[value] # Get key for value
value in b.inverse # Check if value existsUsage examples:
b = bijection({'alice': 1, 'bob': 2})
# Modify through inverse
b.inverse[3] = 'charlie' # bijection({'alice': 1, 'bob': 2, 'charlie': 3})
b.inverse[1] = 'alice_updated' # bijection({'alice_updated': 1, 'bob': 2, 'charlie': 3})
# Delete through inverse
del b.inverse[2] # bijection({'alice_updated': 1, 'charlie': 3})
# Query through inverse
print('alice_updated' in b.inverse.values()) # True - but use b.inverse[1] insteadAccess keys, values, and items like a standard mapping.
def keys(self):
"""Return view of keys.
Returns:
dict_keys: View of bijection keys
"""
def values(self):
"""Return view of values.
Returns:
dict_keys: View of bijection values (same as inverse.keys())
"""
def items(self):
"""Return view of (key, value) pairs.
Returns:
dict_items: View of bijection items
"""Usage examples:
b = bijection({'a': 1, 'b': 2, 'c': 3})
print(list(b.keys())) # ['a', 'b', 'c']
print(list(b.values())) # [1, 2, 3]
print(list(b.items())) # [('a', 1), ('b', 2), ('c', 3)]
# Values are same as inverse keys
print(list(b.values()) == list(b.inverse.keys())) # TrueOperations for copying, clearing, and maintaining bijection state.
def copy(self):
"""Return a shallow copy of the bijection.
Returns:
bijection: New bijection with same mappings
"""
def clear(self):
"""Remove all mappings from the bijection."""
def __eq__(self, other):
"""Check equality with another bijection.
Args:
other: Object to compare with
Returns:
bool: True if other is bijection with same mappings
"""Usage examples:
b1 = bijection({'a': 1, 'b': 2})
b2 = b1.copy()
print(b1 == b2) # True
print(b1 is b2) # False
b1.clear()
print(len(b1)) # 0
print(len(b2)) # 2 - copy unaffectedCommon patterns for working with bijections effectively.
# Swapping keys and values
original = bijection({'name': 'alice', 'age': 25})
swapped = bijection(original.inverse) # {alice': 'name', 25: 'age'}
# Building bidirectional mappings incrementally
mapping = bijection()
for i, name in enumerate(['alice', 'bob', 'charlie']):
mapping[name] = i
# Now mapping['alice'] = 0 and mapping.inverse[0] = 'alice'
# Safe updates preserving bijection property
b = bijection({'a': 1, 'b': 2})
if 'c' not in b and 3 not in b.inverse:
b['c'] = 3 # Safe to add
# Checking for conflicts before assignment
key, value = 'new_key', 'new_value'
if key in b:
print(f"Key {key} already maps to {b[key]}")
if value in b.inverse:
print(f"Value {value} already mapped from {b.inverse[value]}")Understanding bijection constraint violations and common error scenarios.
# KeyError when accessing non-existent keys/values
b = bijection({'a': 1})
try:
value = b['missing']
except KeyError:
print("Key not found")
try:
key = b.inverse[999]
except KeyError:
print("Value not found")
# Bijection automatically handles overwrites
b = bijection({'a': 1, 'b': 2})
b['a'] = 2 # This removes the old 'b': 2 mapping automatically
print(b) # bijection({'a': 2})Install with Tessl CLI
npx tessl i tessl/pypi-collections-extended