Packages

Elixir implementation for apportionment

Current section

Files

Jump to
apportion lib apportion.ex
Raw

lib/apportion.ex

defmodule Apportion do
@moduledoc """
Top level interface, or API, to proportionally distribute a quantity
"""
alias Apportion.Algorithm.EqualProportions
alias Apportion.Setup
alias Apportion.Util
@doc """
Distributes a quantity proportionally among recipients per relative weights using the
'equal proportions' algorithm
## Example
iex> weights = %{a: 41, b: 32, c: 27}
...> Apportion.distribute(weights, 7)
%{a: 3, b: 2, c: 2}
"""
def distribute(weights, quantity, options \\ []) do
portions = Setup.initial_portions(Map.keys(weights), options)
portions_sum = Util.map_values_sum(portions)
Setup.validate(quantity, portions_sum)
next_step(weights, portions, portions_sum, quantity)
end
# recursively
defp next_step(_, portions, portions_sum, quantity) when portions_sum == quantity do
portions
end
defp next_step(weights, portions, portions_sum, quantity) do
key = EqualProportions.recipient(weights, portions)
next_portions = Map.merge(portions, %{key => Map.fetch!(portions, key) + 1})
next_step(weights, next_portions, portions_sum + 1, quantity)
end
end