Extra Python Collections - bags (multisets) and setlists (ordered sets)
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Setlists are ordered collections of unique elements that combine list-like indexing with set-like uniqueness constraints. They maintain insertion order while enforcing element uniqueness, providing efficient index-based access and set operations.
Create ordered sets from iterables with automatic duplicate removal.
class SetList:
def __init__(self, iterable=None, raise_on_duplicate=False):
"""Create a setlist from an iterable.
Args:
iterable: Values to initialize the setlist with
raise_on_duplicate: If True, raise ValueError on duplicate values
"""
def setlist(iterable=None, raise_on_duplicate=False):
"""Create a mutable setlist from an iterable."""
def frozensetlist(iterable=None, raise_on_duplicate=False):
"""Create an immutable, hashable setlist from an iterable."""Usage examples:
from collections_extended import setlist, frozensetlist
# Create from string - duplicates removed, order preserved
sl = setlist('abracadabra')
print(sl) # setlist(('a', 'b', 'r', 'c', 'd'))
# Raise error on duplicates
try:
sl = setlist('hello', raise_on_duplicate=True)
except ValueError:
print("Duplicate 'l' found")
# Create immutable setlist
fsl = frozensetlist([1, 2, 3, 2, 1])
print(len(fsl)) # 3Access and query elements using list-like indexing and sequence operations.
def __getitem__(self, index):
"""Get element at index or slice.
Args:
index: int or slice object
Returns:
Element at index or new setlist for slices
"""
def index(self, value, start=0, end=None):
"""Return index of value between start and end.
Args:
value: Element to find
start: Start index for search
end: End index for search
Returns:
int: Index of the element
Raises:
ValueError: If value not found or outside start-end range
"""
def count(self, value):
"""Return count of value (always 0 or 1 for setlists).
Args:
value: Element to count
Returns:
int: 1 if value in setlist, 0 otherwise
"""
def sub_index(self, sub, start=0, end=None):
"""Return index of a subsequence.
Args:
sub: Sequence to search for
start: Start index for search
end: End index for search
Returns:
int: Index of first element of subsequence
Raises:
ValueError: If subsequence not found
"""Usage examples:
sl = setlist('abcde')
print(sl[2]) # 'c'
print(sl[1:4]) # setlist(('b', 'c', 'd'))
print(sl.index('d')) # 3
print(sl.count('c')) # 1
print(sl.sub_index(['b', 'c'])) # 1Modify setlist contents while maintaining uniqueness constraints.
def append(self, value):
"""Append value to the end.
Args:
value: Value to append
Raises:
ValueError: If value already in setlist
"""
def insert(self, index, value):
"""Insert value at index.
Args:
index: Position to insert at
value: Value to insert
Raises:
ValueError: If value already in setlist
"""
def extend(self, values):
"""Append all values to the end.
Args:
values: Iterable of values to append
Raises:
ValueError: If any value already present or duplicates in values
"""
def remove(self, value):
"""Remove value from setlist.
Args:
value: Element to remove
Raises:
ValueError: If value not present
"""
def pop(self, index=-1):
"""Remove and return item at index.
Args:
index: Index to pop (default: last item)
Returns:
Any: The removed element
"""
def clear(self):
"""Remove all elements from setlist."""
def reverse(self):
"""Reverse the setlist in-place."""
def sort(self, *args, **kwargs):
"""Sort the setlist in-place."""
def swap(self, i, j):
"""Swap elements at indices i and j."""Usage examples:
sl = setlist(['a', 'b', 'c'])
sl.append('d') # setlist(['a', 'b', 'c', 'd'])
sl.insert(1, 'x') # setlist(['a', 'x', 'b', 'c', 'd'])
sl.extend(['e', 'f']) # setlist(['a', 'x', 'b', 'c', 'd', 'e', 'f'])
item = sl.pop() # 'f', setlist now ['a', 'x', 'b', 'c', 'd', 'e']
sl.remove('x') # setlist(['a', 'b', 'c', 'd', 'e'])
sl.reverse() # setlist(['e', 'd', 'c', 'b', 'a'])Mathematical set operations that preserve order based on the left operand.
def union(self, other):
"""Return union of setlists (all elements from both)."""
def intersection(self, other):
"""Return intersection of setlists (common elements)."""
def difference(self, other):
"""Return difference of setlists (elements in self but not other)."""
def symmetric_difference(self, other):
"""Return symmetric difference (elements in either but not both)."""
def __add__(self, other):
"""Concatenate setlists (other elements appended, duplicates raise error)."""
def __sub__(self, other):
"""Return difference of setlists."""
def __and__(self, other):
"""Return intersection of setlists."""
def __or__(self, other):
"""Return union of setlists."""
def __xor__(self, other):
"""Return symmetric difference of setlists."""
def issubset(self, other):
"""Check if all elements are in other."""
def issuperset(self, other):
"""Check if all elements of other are in self."""Usage examples:
sl1 = setlist('abc')
sl2 = setlist('bcd')
print(sl1 | sl2) # setlist(['a', 'b', 'c', 'd']) (union)
print(sl1 & sl2) # setlist(['b', 'c']) (intersection)
print(sl1 - sl2) # setlist(['a']) (difference)
print(sl1 ^ sl2) # setlist(['a', 'd']) (symmetric difference)
print(setlist('ab').issubset(sl1)) # TrueMutable set operations that modify the setlist in-place.
def add(self, item):
"""Add item if not already present (like set.add)."""
def update(self, values):
"""Add all values, ignoring duplicates (like set.update)."""
def discard(self, value):
"""Remove value if present, silent if missing (like set.discard)."""
def discard_all(self, elems_to_delete):
"""Remove all elements in elems_to_delete, ignoring missing."""
def remove_all(self, elems_to_delete):
"""Remove all elements in elems_to_delete.
Raises:
ValueError: If any element not present or duplicates in elems_to_delete
"""
def difference_update(self, other):
"""Remove all elements in other from self."""
def intersection_update(self, other):
"""Keep only elements also in other."""
def symmetric_difference_update(self, other):
"""Update to symmetric difference with other."""Usage examples:
sl = setlist('abc')
sl.add('d') # setlist(['a', 'b', 'c', 'd'])
sl.add('b') # No change - 'b' already present
sl.update('efg') # setlist(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
sl.discard('x') # No error - 'x' not present
sl.discard_all('aei') # Removes 'a' and 'e', ignores 'i'Additional list-like operations for fine-grained control.
def __setitem__(self, index, value):
"""Set element at index to value.
Args:
index: int or slice
value: New value or sequence of values
Raises:
ValueError: If value already exists elsewhere in setlist
"""
def __delitem__(self, index):
"""Delete element at index or slice."""
def shuffle(self, random=None):
"""Shuffle elements in-place.
Args:
random: Random function (default: random.random)
"""Usage examples:
sl = setlist(['a', 'b', 'c', 'd'])
sl[1] = 'x' # setlist(['a', 'x', 'c', 'd'])
del sl[0] # setlist(['x', 'c', 'd'])
sl.shuffle() # Random order, e.g., setlist(['d', 'x', 'c'])Create hashable, immutable versions for use as dictionary keys or set elements.
class frozensetlist(SetList, Hashable):
def __hash__(self):
"""Return hash value for the frozensetlist."""Usage examples:
from collections_extended import frozensetlist
# Immutable setlists can be dict keys
fsl1 = frozensetlist('abc')
fsl2 = frozensetlist('def')
mapping = {fsl1: 'first', fsl2: 'second'}
# Or in sets
setlist_set = {frozensetlist('hello'), frozensetlist('world')}Create copies and compare setlists efficiently.
def copy(self):
"""Return a shallow copy of the setlist."""
def __eq__(self, other):
"""Check equality with another setlist (order matters)."""
def __ne__(self, other):
"""Check inequality with another setlist."""Install with Tessl CLI
npx tessl i tessl/pypi-collections-extended