CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-multiset

An implementation of a multiset data structure with both mutable and immutable variants supporting all standard set operations.

Pending
Overview
Eval results
Files

mutable-operations.mddocs/

Mutable Operations

Mutating operations available exclusively on Multiset instances for modifying multiset contents. These operations modify the multiset in-place and are not available on FrozenMultiset instances.

Capabilities

Element Addition and Removal

Add and remove individual elements with precise multiplicity control.

def add(self, element, multiplicity: int = 1) -> None:
    """
    Add an element to the multiset with specified multiplicity.
    
    Parameters:
    - element: Element to add (must be hashable)
    - multiplicity: Number of times to add element (default: 1)
    
    Raises:
    ValueError: If multiplicity is negative
    """

def remove(self, element, multiplicity: Optional[int] = None) -> int:
    """
    Remove element from multiset and return removed multiplicity.
    
    Parameters:
    - element: Element to remove
    - multiplicity: Number to remove (default: remove all)
    
    Returns:
    Number of elements actually removed
    
    Raises:
    KeyError: If element not present in multiset
    """

def discard(self, element, multiplicity: Optional[int] = None) -> int:
    """
    Remove element from multiset without raising error if not present.
    
    Parameters:
    - element: Element to remove  
    - multiplicity: Number to remove (default: remove all)
    
    Returns:
    Number of elements actually removed (0 if not present)
    """

def pop(self, element, default: int) -> int:
    """
    Remove element and return its multiplicity.
    
    Parameters:
    - element: Element to remove
    - default: Value to return if element not present
    
    Returns:
    Multiplicity of removed element or default value
    
    Raises:
    KeyError: If element not present and no default provided
    """

def clear(self) -> None:
    """Remove all elements from the multiset."""

Usage Examples:

from multiset import Multiset

ms = Multiset('aab')      # {'a': 2, 'b': 1}

# Add elements
ms.add('c')               # Add 'c' once: {'a': 2, 'b': 1, 'c': 1}
ms.add('a', 3)            # Add 'a' three times: {'a': 5, 'b': 1, 'c': 1}

# Remove elements
removed = ms.remove('a', 2)    # Remove 2 'a's, returns 2: {'a': 3, 'b': 1, 'c': 1}
removed = ms.discard('z', 1)   # Try to remove 'z', returns 0: unchanged
removed = ms.remove('b')       # Remove all 'b's, returns 1: {'a': 3, 'c': 1}

# Pop elements
count = ms.pop('c')            # Remove and return count of 'c': 1
count = ms.pop('z', 0)         # Pop 'z' with provided default: returns 0

# Clear all
ms.clear()                     # Empty multiset: {}

Direct Assignment Operations

Set element multiplicities directly using dictionary-like assignment.

def __setitem__(self, element, multiplicity: int) -> None:
    """
    Set the multiplicity of an element directly.
    
    Parameters:
    - element: Element to set multiplicity for
    - multiplicity: New multiplicity (removes element if 0)
    
    Raises:
    ValueError: If multiplicity is negative
    """

def __delitem__(self, element) -> None:
    """
    Remove element completely from multiset.
    
    Parameters:
    - element: Element to remove
    
    Raises:
    KeyError: If element not present
    """

def setdefault(self, element, default: int = 1) -> int:
    """
    Get multiplicity of element, setting to default if not present.
    
    Parameters:
    - element: Element to get or set
    - default: Multiplicity to set if element not present
    
    Returns:
    Current or newly set multiplicity
    """

Usage Examples:

ms = Multiset('ab')       # {'a': 1, 'b': 1}

# Direct assignment
ms['c'] = 3               # Set 'c' to multiplicity 3: {'a': 1, 'b': 1, 'c': 3}
ms['a'] = 5               # Change 'a' to multiplicity 5: {'a': 5, 'b': 1, 'c': 3}
ms['b'] = 0               # Remove 'b' by setting to 0: {'a': 5, 'c': 3}

# Delete elements
del ms['c']               # Remove 'c' completely: {'a': 5}

# Set with default
count = ms.setdefault('x', 2)  # Set 'x' to 2, returns 2: {'a': 5, 'x': 2}
count = ms.setdefault('a', 10) # 'a' exists, returns 5: unchanged

Bulk Update Operations

Update multiset contents from other collections with various combination strategies.

def update(self, *others, **kwargs) -> None:
    """
    Add elements from others to this multiset (sum multiplicities).
    
    Parameters:
    - *others: Iterables or mappings to add elements from
    - **kwargs: Additional element-multiplicity pairs
    """

def union_update(self, *others) -> None:
    """
    Update multiset with union of this multiset and others.
    Takes maximum multiplicity for each element.
    
    Parameters:
    - *others: Iterables or mappings to union with
    """

def intersection_update(self, *others) -> None:
    """
    Update multiset with intersection of this multiset and others.
    Keeps only common elements with minimum multiplicities.
    
    Parameters:
    - *others: Iterables or mappings to intersect with
    """

def difference_update(self, *others) -> None:
    """
    Remove elements of others from this multiset.
    
    Parameters:
    - *others: Iterables or mappings to subtract
    """

def symmetric_difference_update(self, other) -> None:
    """
    Update multiset with symmetric difference.
    
    Parameters:
    - other: Iterable or mapping to compute symmetric difference with
    """

def times_update(self, factor: int) -> None:
    """
    Scale all multiplicities by factor in-place.
    
    Parameters:  
    - factor: Scaling factor (must be non-negative)
    
    Raises:
    ValueError: If factor is negative
    """

Usage Examples:

ms = Multiset('aab')      # {'a': 2, 'b': 1}

# Update (combine/add multiplicities)
ms.update('abc')          # Add from string: {'a': 3, 'b': 2, 'c': 1}
ms.update({'x': 2, 'y': 1}) # Add from mapping: {'a': 3, 'b': 2, 'c': 1, 'x': 2, 'y': 1}

# Union update (maximum multiplicities)
ms2 = Multiset('aaax')    # {'a': 3, 'x': 1}
ms.union_update(ms2)      # Take max: {'a': 3, 'b': 2, 'c': 1, 'x': 2, 'y': 1}

# Intersection update (minimum multiplicities, common elements only)
ms.intersection_update('axyz')  # Keep common: {'a': 1, 'x': 1, 'y': 1}

# Difference update (subtract)
ms.difference_update('ay')      # Remove: {'x': 1}

# Times update (scale)
ms.times_update(3)              # Scale by 3: {'x': 3}

In-Place Operators

Convenient operators for in-place multiset operations.

def __ior__(self, other) -> Multiset:
    """In-place union using |= operator."""

def __iand__(self, other) -> Multiset:
    """In-place intersection using &= operator."""

def __isub__(self, other) -> Multiset:
    """In-place difference using -= operator."""

def __ixor__(self, other) -> Multiset:
    """In-place symmetric difference using ^= operator."""

def __imul__(self, factor: int) -> Multiset:
    """In-place scaling using *= operator."""

Usage Examples:

ms1 = Multiset('aab')     # {'a': 2, 'b': 1}
ms2 = Multiset('abc')     # {'a': 1, 'b': 1, 'c': 1}

# In-place operations using operators
ms1 |= ms2                # Union: {'a': 2, 'b': 1, 'c': 1}
ms1 &= 'ab'               # Intersection: {'a': 1, 'b': 1}  
ms1 -= 'a'                # Difference: {'b': 1}
ms1 *= 4                  # Scale: {'b': 4}

# Note: += uses update() method for combination
ms1 += 'bb'               # Combine: {'b': 6}

Mutable-Specific Features

Features that distinguish mutable multisets from their immutable counterparts.

Mutability Characteristics:

# Mutable multisets can be modified after creation
ms = Multiset('abc')
ms.add('d')                    # Allowed on Multiset
ms['e'] = 2                    # Allowed on Multiset

# Immutable multisets cannot be modified
frozen_ms = FrozenMultiset('abc')
# frozen_ms.add('d')           # AttributeError: not available
# frozen_ms['e'] = 2           # TypeError: not supported

# Mutable multisets are not hashable
# hash(ms)                     # TypeError: unhashable type
hash(frozen_ms)                # Works: returns hash value

# Use in sets/dicts
my_set = {frozen_ms}           # Allowed
# my_set = {ms}                # TypeError: unhashable type

Thread Safety Considerations:

# Mutable multisets are not thread-safe
# Concurrent modifications require external synchronization
import threading

ms = Multiset()
lock = threading.Lock()

def safe_add(element):
    with lock:
        ms.add(element)

# Use FrozenMultiset for read-only sharing between threads
shared_ms = FrozenMultiset('abc')  # Safe to share

Performance Notes:

# Bulk operations are more efficient than individual operations
ms = Multiset()

# Efficient: single bulk operation
ms.update('abcdefg' * 1000)

# Less efficient: many individual operations  
# for char in 'abcdefg' * 1000:
#     ms.add(char)

# In-place operations modify existing multiset
ms = Multiset('aaa')
original_id = id(ms)
ms += 'bbb'                    # Modifies existing multiset
assert id(ms) == original_id   # Same object

# Regular operations create new multisets
result = ms + 'ccc'            # Creates new multiset
assert id(result) != id(ms)    # Different objects

Install with Tessl CLI

npx tessl i tessl/pypi-multiset

docs

element-management.md

index.md

mutable-operations.md

set-operations.md

tile.json