Accepted Answer written in R
I was looking for this question/solution, but I'm working in R, so I have re-written @Maciek's answer above in R for anyone that passes this way. I kept it as close as I could to the original answer in Python.
library(dplyr)
scale_ratio <- function(ratios){
sum_ <- sum(ratios)
return(ratios/sum_)
}
ratio_breakdown_recursive <- function(x, ratios){
top_ratio <- ratios[1]
part <- round(x*top_ratio)
if (x <= part){
return(x)
}
x <- (x - part)
c(part, ratio_breakdown_recursive(x, scale_ratio(ratios[2:length(ratios)])))
}
ratio_breakdown <- function(x, ratios){
x <- x[1]
sorted_ratio = sort(ratios, decreasing = TRUE)
stopifnot(round(sum(ratios)) == 1)
sorted_result = ratio_breakdown_recursive(x, sorted_ratio)
stopifnot(sum(sorted_result) == x)
# Now, we have to reverse the sorting and add missing zeros
sorted_result <- append(sorted_result, rep(0, length(ratios) - length(sorted_result)))
numbered_ratios <- data.frame(ratios, seq_along(ratios))
sorted_numbered_ratios <- arrange(numbered_ratios, desc(ratios))
combined <- cbind(sorted_numbered_ratios, sorted_result)
combined_unsorted <- arrange(combined, seq_along.ratios.)
unsorted_results <- combined_unsorted[,3]
return(unsorted_results)
}
> ratio_breakdown(7, c(0.36, 0.44,0.07,0.07,0.03,0.03))
[1] 3 3 0 1 0 0
> ratio_breakdown(10, c(0.55,0.45))
[1] 6 4
> ratio_breakdown(16, c(0.16,0.47,0.13,0.24))
[1] 2 8 2 4
I realize the first answer returns a different order than @Maciek's answer, but for my purposes, this worked, and if someone comes along and can improve my R code, be my guest -- I'm happy to learn.