Skip to content

Instantly share code, notes, and snippets.

@klesse413
Created July 27, 2017 01:19
Show Gist options
  • Save klesse413/ed24946dbf17a3273929d5cad3f1a7b3 to your computer and use it in GitHub Desktop.
Save klesse413/ed24946dbf17a3273929d5cad3f1a7b3 to your computer and use it in GitHub Desktop.
module Allocator
module_function
def allocate(inflow, weightings)
raise 'Inflow and weightings must be present' unless [inflow, weightings].all?(&:present?)
raise 'Inflow and weightings must be Integers' unless (weightings + [inflow]).all? { |input| input.is_a?(Integer) }
allocations, remainders = apportion_with_remainder(inflow, weightings).transpose
remaining_inflow = inflow - allocations.sum
deserving_indices = remainders.each_with_index.sort_by { |remainder, i| [remainder, i] }.reverse.map { |_remainder, i| i }.first(remaining_inflow)
allocations.each_with_index.map do |allocation, i|
deserving_indices.include?(i) ? allocation + 1 : allocation
end
end
def apportion_with_remainder(input, buckets)
total = buckets.sum
buckets.map do |bucket|
(input * bucket).divmod(total)
end
end
end
@amadeann
Copy link

amadeann commented Dec 2, 2021

The article explaining the logic behind the code:
https://www.betterment.com/engineering/penny-precise-allocation-functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment