Verified Commit d3d28777 authored by Jakob Moser's avatar Jakob Moser
Browse files

Add get_equivalence_class util method

This way, we can partition songs into equivalence classes based on identicalness
parent 8988bb82
Loading
Loading
Loading
Loading
+4 −0
Changes for karaokatalog/util/__init__.py: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
"""
Utility functions completely independent of the root project (i.e., you could copy
them to any other code project and they'd immediately work).
"""
+32 −0
Changes for karaokatalog/util/get_equivalence_classes.py: 32 added lines, 0 removed lines.
Original line number Diff line number Diff line
from collections.abc import Iterable, Sequence, Callable

type EquivalenceClass[T] = Sequence[T]


def get_equivalence_classes[T](
    items: Iterable[T], is_equivalent: Callable[[T, T], bool]
) -> Sequence[EquivalenceClass[T]]:
    """
    Partition an iterable of items into equivalence classes under the given equivalence relation.
    The order of `items` is kept within the equivalence classes.

    >>> from math import floor
    >>> get_equivalence_classes([1.0, 2.1, 1.1, 1.0, 2.2, 2.1, 3.3], lambda a, b: floor(a) == floor(b))
    ((1.0, 1.1, 1.0), (2.1, 2.2, 2.1), (3.3,))
    """
    equivalence_classes: list[list[T]] = []

    for item in items:
        # Check if the item belongs into an already existing equivalence class
        for equivalence_class in equivalence_classes:
            # Pick an arbitrary representative of the equivalence class (we are allowed to do this
            # because it is an equivalence class)
            representative = equivalence_class[0]
            if is_equivalent(item, representative):
                equivalence_class.append(item)
                break
        else:
            # This item forms a new equivalence class, so we create one containing only the item and append it
            equivalence_classes.append([item])

    return tuple(tuple(equivalence_class) for equivalence_class in equivalence_classes)