I was asked a programming question by a friend about how to determine all possible combinations of values from a set can be added to make a desired total. I have a solution, but it is less than elegant (its basically just a series of for-loops and if-statements). I'm sure dplyr has a solution that I can't think of, as I know how useful it is but I just haven't gotten very good at it yet. I will post the question and my script below.
Question: There is a target with six rings on it, each ring is worth a different value. These values are either 1, 2, 3, 4, 5, or 6. How many different combinations of rings can you use to score EXACTLY 9 points?
So to consider: Order is not important You can use as few or as many values as you want You can get the same value more than once (so 9 1's is a totally valid option)
I had considered first using combn() from combinat package, but combn() does not replace values.
Then I decided to use a series of nested for loops and if statements (I truncated it to where you could only use a max of 6-values, because while I may have free time, I'm not a masochist about to write a loop that allows up to 9-values). So essentially, it is running through 6 for-loops worth of possible values. I included the number 0 to the list of possible values to represent no attempt when I only need 2 values instead of 6 (so 4+5+0+0+0+0 is a valid output in this loop, but it wouldn't be able to do 4+5 as it would always try to add more non-zero values).
## Create a vector x with possible values
x = c(1,2,3,4,5,6)
## Add in value 0 because I need to be able to write this dumb loop that allows many terms to be used, but also allows smaller amounts of terms to be used
x = c(x,0);x
## Creating empty data.frame to input solutions to so that I can check for uniqueness of solution
df = data.frame("a" = as.numeric(),
"b" = as.numeric(),
"c" = as.numeric(),
"d" = as.numeric(),
"e" = as.numeric(),
"f" = as.numeric())
for (a in x){
for (b in x){
for (c in x){
for (d in x){
for (e in x){
for (f in x){
m = sum(a,b,c,d,e,f)
if(m == 9) {
p = 0
n = c(a,b,c,d,e,f)
if (nrow(df) == 0){
df[1,] = n
}
if (nrow(df) >= 1){
for (i in (1:nrow(df))){
if(setequal(n,df[i,]) == TRUE){
p = p+1
}}
if(p == 0){
df = rbind(df,n)
}
}
}
}
}
}
}
}
}
## Convert any 0 values to NA
df[df==0] = NA
## Check Solutions
df
I created an empty data.frame to store solutions, and then within the loop, I created a test to see if a new solution in the loop matches a combination of values previously found, and if so, it would not rbind() that to the data.frame.
I'm sure there is a better way to do this, one that allows a dynamic max number of values (so it could be soft coded in this case to change the max number of values in each solution to 9 instead of my hard-coded 6, or drop it to 5 if my desired total was 5 instead of 9). If you have any suggestions to make this less of a clunky, loop-filled mess, it would be appreciated!