Functional Weave
Code in TypeScript

money.allocate@1.0.0

impl/python.py

1,279 bytes · the Python implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

from typing import List, Sequence

from .money_amount import Money, money  ← from money.amount ^1.0.0 · built alongside by fune


def allocate(amount: Money, ratios: Sequence[int]) -> List[Money]:
    """Split ``amount`` across ``ratios`` so the parts add back up to the whole.

    Splitting 10.00 three ways gives 3.34, 3.33, 3.33 - never 3.33 three times
    with a penny quietly lost. The leftover goes to the largest remainders,
    ties broken by position, so the split is stable and reproducible.
    """
    if len(ratios) == 0:
        raise ValueError("allocate needs at least one ratio")
    if any(isinstance(r, bool) or not isinstance(r, int) for r in ratios):
        raise TypeError("ratios must be integers")
    total = sum(ratios)
    if total == 0:
        raise ValueError("ratios must not sum to zero")

    bases = []
    remainders = []
    for ratio in ratios:
        numerator = amount.minor * ratio
        base = numerator // total
        bases.append(base)
        remainders.append(numerator - base * total)

    leftover = amount.minor - sum(bases)

    order = sorted(range(len(ratios)), key=lambda i: (-remainders[i], i))
    for index in order:
        if leftover <= 0:
            break
        bases[index] += 1
        leftover -= 1

    return [money(base, amount.currency) for base in bases]