CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-collections-extended

Extra Python Collections - bags (multisets) and setlists (ordered sets)

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

bijections.mddocs/

Bijections and One-to-One Mappings

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.

Capabilities

Bijection Construction

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)

Inverse Relationship

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'

Mapping Operations

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})

Inverse Operations

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 exists

Usage 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] instead

View Operations

Access 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()))  # True

Bijection Maintenance

Operations 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 unaffected

Advanced Usage Patterns

Common 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]}")

Error Handling

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

docs

bags.md

bijections.md

index.md

indexed-dicts.md

range-maps.md

setlists.md

tile.json