from typing import List, Sequence from .money_amount import Money, money 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]