2

I have three variables: X, Y, and Z. I want to find all the combinations of X, Y and Z that add up to 100. X, Y and Z can only take values between [0,100]. The ouput should look somehtinkg like this:

  X   Y   Z   Sum
100   0   0   100
 99   1   0   100
 99   0   1   100
 98   2   0   100
 98   1   1   100
 98   0   2   100

and so on...

Any suggestion on how to get all the possible combinations?

Agarp
  • 433
  • 7
  • 15
  • Suggested dupes: [r - Unique Combinations of all elements from two or more vectors](https://stackoverflow.com/q/11388359/903061), [How to generate matrix of combinations?](https://stackoverflow.com/q/3993546/903061). Generate all combinations, use `rowSums`, and subset where the row sums `== 100`. – Gregor Thomas Oct 16 '17 at 20:00
  • The best way I can find is to fix one number as constant and the question will be much easier. For example, when x = 0, there are 101 combinations of y and z. when x = 1, there are 100 combinations of y and z. So on so forth. – Arthur Oct 16 '17 at 20:02
  • 1
    `partitions::composition(100, 3)`; [Generating all permutations of N balls in M bins](https://stackoverflow.com/questions/27064675/generating-all-permutations-of-n-balls-in-m-bins/27064925#27064925) – Henrik Oct 16 '17 at 20:10
  • Is the `Sum` column really necessary? – Rich Scriven Oct 16 '17 at 20:15

2 Answers2

5

An alternative (perhaps more efficient for large numbers) would be

df <- do.call(rbind, lapply(0:100, function(i) data.frame(x=i, y=0:(100-i))))
df$z <- 100-df$x-df$y
Andrew Gustar
  • 17,295
  • 1
  • 22
  • 32
  • 1
    This is likely to scale better than my solution, since you're only generating the correct rows, rather than all combinations and then subsetting. Going much above 0:100 is using a fair amount of RAM with my method. – Eric Watt Oct 16 '17 at 20:36
4

Since you're limited to 1:100 on only three columns, this is easy to brute force. Would need a more clever solution if the range was larger.

library(data.table)

df <- expand.grid(X = 0:100,
                  Y = 0:100,
                  Z = 0:100)

setDT(df)

df[, Sum := X + Y + Z]
df[Sum == 100]
#         X Y   Z Sum
#    1: 100 0   0 100
#    2:  99 1   0 100
#    3:  98 2   0 100
#    4:  97 3   0 100
#    5:  96 4   0 100
#   ---              
# 5147:   1 1  98 100
# 5148:   0 2  98 100
# 5149:   1 0  99 100
# 5150:   0 1  99 100
# 5151:   0 0 100 100
Eric Watt
  • 3,180
  • 9
  • 21
  • Nice solution! I was working with `expand.grid` all the past week but I didn't think of it! – Arthur Oct 16 '17 at 20:03
  • Or more simply `df[(X + Y + Z) == 100]` – Rich Scriven Oct 16 '17 at 20:06
  • 1
    @RichScriven True, but need to add a Sum column to get the output in the OP. Could make it `df[(X + Y + Z) == 100, .(X, Y, Z, Sum = 100)]` but I'm not sure if that's much clearer than the two step. – Eric Watt Oct 16 '17 at 20:09
  • 1
    Oh I see. I don't really see the point of the extra column though. We can be confident that they will all be 100 if we do it right. – Rich Scriven Oct 16 '17 at 20:10
  • A less memory intensive way would be to `expand.grid` on just `X` and `Y`, filter for `X+Y<=100` and then calculate `Z`. – Andrew Gustar Oct 17 '17 at 05:36