1

I have a list of two-element vectors. From this list, I'd like to find n vectors (not necessarily distinct) (x,y), such that the sum of the ys of these vectors is larger or equal to a number k. If multiple vectors satisfy this condition, select the one where the sum of the xs is the smallest.

For example, I'd like to find n=2 vectors (x1,y1) and (x2,y2) such that y1+y2 >= k. If there are more than just one which satisfies this condition, select the one where x1+x2 is the smallest.

I've so far only managed to set-up the following code:

X <- c(3, 2, 3, 8, 7, 7, 13, 11, 12, 12)
Y <- c(2, 1, 3, 6, 5, 6, 8, 9, 10, 9)

df <- data.frame(A, B)
l <- list()
for (i in seq(1:nrow(df))){
  n <- as.numeric(df[i,])
  l[[i]] <- n
}

Using the values above, let's say n=1, k=9, then I'll pick the tuple (x,y)=(11,9) because even though (12,9) also matches the condition that y=k, the x is smaller.

If n=2, k=6, then I'll pick (x1,y1)=(3,3) and (x2,y2)=(3,3) because it's the smallest x1+x2 that satisfies y1+y2 >= 6.

If n=2, k=8, then I'll pick (x1,y1)=(3,3) and (x2,y2)=(7,5) because y1+y2>=8 and in the next alternative tuples (3,3) and (8,6), 3+8=11 is larger than 3+7.

I feel like a brute-force solution would be possible: all possible n-sized combinations of each vector with the rest, for each permutation calculate yTotal=y1+y2+y3... find all yTotal combinations that satisfy yTotal>=k and of those, pick the one where xTotal=x1+x2+x3... is minimal.

I definitely struggle putting this into R-code and wonder if it's even the right choice. Thank you for your help!

guestman
  • 13
  • 3
  • I believe the mathematical term for such sets is "partitions". Perhaps that will accelerate your efforts at searching. When I ran `sos::findFn("partitions")`, I got `# found 803 matches;` including a bunch in a package called "partitions". – IRTFM Mar 28 '17 at 22:18

1 Answers1

0

First, it seems from your question that you allow to select from Y with replacement. The code basically does your brute-force approach: use the permutations in the gtools library to generate the permutations. Then basically do the filtering for sum(Y)>=k, and ordering first by smallest sum(Y) and then sum(X).

X <- c(3, 2, 3, 8, 7, 7, 13, 11, 12, 12)
Y <- c(2, 1, 3, 6, 5, 6, 8, 9, 10, 9)
n<-1
perm<-gtools::permutations(n=length(Y),r=n, repeats.allowed=T)
result<-apply(perm,1,function(x){ c(sum(Y[x]),sum(X[x])) })
dim(result) # 2 10

k=9 ## Case of n=1, k=9
keep<-which(result[1,]>=k)
result[,keep[order(result[1,keep],result[2,keep])[1]]] # 9 and 11

##### n=2 cases ##########
n<-2
perm<-gtools::permutations(n=length(Y),r=n, repeats.allowed=T)
result<-apply(perm,1,function(x){ c(sum(Y[x]),sum(X[x])) })
dim(result) # 2 100

## n=2, k=6
keep<-which(result[1,]>=6)
        keep[order(result[1,keep],result[2,keep])[1]]  # the 23 permutation
perm[23,]                                              # 3 3 is (Y1,Y2)
result[,keep[order(result[1,keep],result[2,keep])[1]]] # sum(Y)=6 and sum(X)=6

## n=2, k=8
keep<-which(result[1,]>=8)
        keep[order(result[1,keep],result[2,keep])[1]]  # the 6 permutation
perm[6,]                                               # 1 6 is (Y1,Y2)
result[,keep[order(result[1,keep],result[2,keep])[1]]] # sum(Y)=8 and sum(X)=10
fishtank
  • 3,718
  • 1
  • 14
  • 16
  • Thank you so much! This works very well and helps me slowly grasp the intricacies of R just a tad more. Brute-force doesn't scale well with larger source vectors of course, as the permutations-array becomes exponentially larger. In my use case the vectors contain around 600 items, so I'll have to look into ways of shrinking the vector or maybe finding a different approach. – guestman Mar 29 '17 at 17:54