Find index of element comparing with sorted vector - r

If I have a sorted vector, like
vec <- c(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
and I have
x <- 9.5
Then x is between the 5th and 6th value in my sorted row, and I want to get the index 5. How can I do it?

The following will give the result you're looking for:
x<-c(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
findInterval(9.5,x)
> [1] 5
Alternative solutions include:
> max(which(x < 9.5))
[1] 5

There should be multiple ways to do this. One way using which.max
which.max(vec > x) - 1
#[1] 5
This finds first index where vec is greater than x and then returns an index 1 less than that.
As it is sorted the opposite should work as well
which.min(vec < x) - 1
#[1] 5

Related

Blackjack aces sequence

I have a sequence say: 11, 11, 6, 4, 11, 10, 6,... which simulates the following possible card values for a player's hand in blackjack.
When the sum of these numbers accumulates to 11 or greater, I am trying to make each value of 11 which occurs after this point equal to 1.
Where the cumulative sum is: 11, 22, 28, 32,...
Desired outcome: 11, 1, 6, 4, 1, 10, 6,...
Here is what I have been unsuccessfully trying with:
nphand = c(11,11,6,4,11,10,6)
v=cumsum(nphand)
p=v[v<=11]
for (i in (length(p)+1):length(nphand)){
if (nphand[i]==11){
nphand[i]==1
}
}
Any help and/or advice would be greatly appreciated.
This should work.
nphand = c(11,11,6,4,11,10,6)
v=cumsum(nphand)
p=v[v<=11]
for (i in 1:length(nphand)){
cards <- nphand[1:i]
elevens <- cards[-1] %in% 11
if(sum(cards)>=11 & sum(elevens) >=1){
cards[which(elevens) +1] <- 1
}
nphand[1:i] <- cards
}
> nphand
[1] 11 1 6 4 1 10 6
This looks like it is dependent on the first card being 11. The solution below should work regardless:
nphand = c(2,11,6,4,11,10,6)
v=cumsum(nphand)
p=v[v<=11]
for (i in 1:length(nphand)){
cards <- nphand[1:i]
elevens <- cards %in% 11
if(sum(cards)>=11 & sum(elevens) >=1){
cards[which(elevens[-1]) + 1] <- 1
}
nphand[1:i] <- cards
}

Finding n tuples from a list whose aggregation satisfies a condition

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!
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

R-Randomly pick a number and do it over and over until a condition is achivied

I want to randomly pick a number from a vector with 8 elements that sums to 35. If the number is 0 look for another number. If the number is greater than 0, make this number -1. Do this in a loop until the sum of the vector is 20. How can I do this in R?
For example: vec<-c(2,3,6,0,8,5,6,5)
Pick a number from this list randomly and make the number -1 until the sum of the elements becomes 20.
I'm really really not sure that is what you want, but for what I understand of your question, here is my solution. You'll get most of the concept and key fonctions in my script. Use that and help() to understand them and optimize it.
vec <- c(2, 3, 6, 0, 8, 5, 6, 5)
summ <- 0
new.vec <- NULL
iter <- 1
while(summ<20) {
selected <- sample(vec,1)
if(selected!=0) new.vec[iter] <- selected-1
summ <- sum(new.vec)
iter <- iter+1
}
Try this:
vec <- c(2, 3, 6, 0, 8, 5, 6, 5)
#just setting the seed for reproducibility
set.seed(19)
tabulate(sample(rep(seq_along(vec),vec),20))
#[1] 0 2 4 0 4 5 3 2

subsetting a range between two percentages (R)

I have a numeric vector consisting of 150 observations ranging from -217544 to 319842.
I would like to create a subset based on a range of percentages. In other words I would like to subset everything between 30% and 70%.
for instance:
bm.sort <- c(1, 2, 3, 4, 5, 6, 7, 8, 9 ,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
I would like for the code to select the middle 40% (7 to 14).
I have so far tried the code
bm.m <- subset(bm.sort, bm.sort >= quantile(bm.sort, 0.3 %between% bm.sort <= quantile(bm.sort, 0.7)))
and
bm.m <- subset(bm.sort, bm.sort >= quantile(bm.sort, 0.3 | bm.sort <= quantile(bm.sort, 0.7)))
However when I use this code I only receive one observation instead of the range of 60 observations that i should receive.
Any help would be appreciated.
I managed to figure it out (missing ")" ), sorry for taking up your time unnecessarily.
Thank you for all the help.

Extract several instances of a sequence from vector

Suppose I have a numeric vector vec from which I would like to extract several instances of sequence seq that are scattered all over. The sequence's starting indexes in vec are known. Ex.:
seq <- c(6, 4, 9)
vec <- c(6, 6, 4, 9, 9, 6, 4, 9, 5, 6, 6, 4, 9, 6, 4)
seq_index <- c(2, 6, 11)
What I would like to get is someting like this:
6, 6, 6
4, 4, 4
9, 9, 9
What obviously does not work is:
vec[seq_index:seq_index + length(seq) - 1]
I also played around with the apply family of functions, e.g.
lapply(X = vec, FUN = `[`, cbind(seq_index, seq_index + length(seq) - 1))
which also does not yield the expected result.
I am sure I am missing something fundamental here but cannot figure it out.
Any pointers would be highly appreciated.
Perhaps you mean this:
sapply(seq_index, function(i) vec[i:(i+length(seq)-1)])
# [,1] [,2] [,3]
#[1,] 6 6 6
#[2,] 4 4 4
#[3,] 9 9 9

Resources