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
}
Related
I just want to fill this matrix, I know this is a very easy problem, but I'm not good at all.
I won't use these numbers in the matrix.
I had tried with for loop, but the problem is this loop only shows the last iteration.
I repeat, I don't want the numbers from 1 to 9.
I have this:
(mat<-matrix(0, nrow = 3, ncol = 3))
for (i in 1:3) {
for (j in 1:3) {
if (j==1 & i==1) {
mat[i,j]=6
} else if (j==1 & i==2) {
mat[i,j]=7
} else if (j==1 & i==3) {
mat[i,j]=8
}
}
}
I want a code whithout put the conditions & i==1, & i==2, & i==3.
I want to make another variable k from 1 to 3. I tried this, but the loop only show me the value in 3.
Thank you so much.
Edit: I'm going to show you an example abou I want to solve. You will see that's about the same problem. I have the next data frame:
base2<-c( 20, 15, 17, 23, 19, 21, 16, 22, 18)
base2.1<-c( 6, 5, 3, 4, 1, 7, 2, 9, 8)
base3<-data.frame(base2,base2.1)
names(base3)=c("age","mean")
base3
I want to fill a vector vec where vec[1]=5 (because as you can see,age=15), vec[2]=2 (because ,age=16) and so on, so on.
I have tried this just for the first element:
(vec<-c(rep(0,length(base3$mean))))
for (i in 1:length(base3$mean)) {
if (base3$age[i]==15) {
vec[1]=base3$mean[which(base3$age==15)]
}
}
vec
Of course, I don't want to put number 1 on this part of the loop: vec[1]=base3$mean[which(base3$age==15)
If I want to fill the entire vector, I have this:
for (i in 1:length(base3$mean)) {
for (j in sort(base3$age)) {
vec[i]=base3$mean[which(base3$age==j)]
}
}
vec
But the foor loop only show me the last iteration:
# [1] 4 4 4 4 4 4 4 4 4
I want the next result:
[1] 5 2 3 8 1 6 7 9 4
This is simply to order vector age and use the index returned to index vector mean.
i <- order(base3$age)
vec <- base3$mean[i]
vec
#[1] 5 2 3 8 1 6 7 9 4
See help("order"), and the difference to sort.
A one-liner is
vec <- base3$mean[order(base3$age)]
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
I have a vector:
as <- c(1,2,3,4,5,9)
I need to extract the first continunous sequence in the vector, starting at index 1, such that the output is the following:
1 2 3 4 5
Is there a smart function for doing this, or do I have to do something not so elegant like this:
a <- c(1,2,3,4,5,9)
is_continunous <- c()
for (i in 1:length(a)) {
if(a[i+1] - a[i] == 1) {
is_continunous <- c(is_continunous, i)
} else {
break
}
}
continunous_numbers <- c()
if(is_continunous[1] == 1) {
is_continunous <- c(is_continunous, length(is_continunous)+1)
continunous_numbers <- a[is_continunous]
}
It does the trick, but I would expect that there is a function that can already do this.
It isn't clear what you need if the index of the continuous sequence only if it starts at index one or the first sequence, whatever the beginning index is.
In both case, you need to start by checking the difference between adjacent elements:
d_as <- diff(as)
If you need the first sequence only if it starts at index 1:
if(d_as[1]==1) 1:(rle(d_as)$lengths[1]+1) else NULL
# [1] 1 2 3 4 5
rle permits to know lengths and values for each consecutive sequence of same value.
If you need the first continuous sequence, whatever the starting index is:
rle_d_as <- rle(d_as)
which(d_as==1)[1]+(0:(rle_d_as$lengths[rle_d_as$values==1][1]))
Examples (for the second option):
as <- c(1,2,3,4,5,9)
d_as <- diff(as)
rle_d_as <- rle(d_as)
which(d_as==1)[1]+(0:(rle_d_as$lengths[rle_d_as$values==1][1]))
#[1] 1 2 3 4 5
as <- c(4,3,1,2,3,4,5,9)
d_as <- diff(as)
rle_d_as <- rle(d_as)
which(d_as==1)[1]+(0:(rle_d_as$lengths[rle_d_as$values==1][1]))
# [1] 3 4 5 6 7
as <- c(1, 2, 3, 6, 7, 8)
d_as <- diff(as)
rle_d_as <- rle(d_as)
which(d_as==1)[1]+(0:(rle_d_as$lengths[rle_d_as$values==1][1]))
# [1] 1 2 3
A simple way to catch the sequence would be to find the diff of your vector and grab all elements with diff == 1 plus the very next element, i.e.
d1<- which(diff(as) == 1)
as[c(d1, d1[length(d1)]+1)]
NOTE
This will only work If you only have one sequence in your vector. However If we want to make it more general, then I 'd suggest creating a function as so,
get_seq <- function(vec){
d1 <- which(diff(as) == 1)
if(all(diff(d1) == 1)){
return(c(d1, d1[length(d1)]+1))
}else{
d2 <- split(d1, cumsum(c(1, diff(d1) != 1)))[[1]]
return(c(d2, d2[length(d2)]+1))
}
}
#testing it
as <- c(3, 5, 1, 2, 3, 4, 9, 7, 5, 4, 5, 6, 7, 8)
get_seq(as)
#[1] 3 4 5 6
as <- c(8, 9, 10, 11, 1, 2, 3, 4, 7, 8, 9, 10)
get_seq(as)
#[1] 1 2 3 4
as <- c(1, 2, 3, 4, 5, 6, 11)
get_seq(as)
#[1] 1 2 3 4 5 6
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
I have the following matrix
m <- matrix(c(2, 4, 3, 5, 1, 5, 7, 9, 3, 7), nrow=5, ncol=2,)
colnames(x) = c("Y","Z")
m <-data.frame(m)
I am trying to create a random number in each row where the upper limit is a number based on a variable value (in this case 1*Y based on each row's value for for Z)
I currently have:
samp<-function(x){
sample(0:1,1,replace = TRUE)}
x$randoms <- apply(m,1,samp)
which work works well applying the sample function independently to each row, but I always get an error when I try to alter the x in sample. I thought I could do something like this:
samp<-function(x){
sample(0:m$Z,1,replace = TRUE)}
x$randoms <- apply(m,1,samp)
but I guess that was wishful thinking.
Ultimately I want the result:
Y Z randoms
2 5 4
4 7 7
3 9 3
5 3 1
1 7 6
Any ideas?
The following will sample from 0 to x$Y for each row, and store the result in randoms:
x$randoms <- sapply(x$Y + 1, sample, 1) - 1
Explanation:
The sapply takes each value in x$Y separately (let's call this y), and calls sample(y + 1, 1) on it.
Note that (e.g.) sample(y+1, 1) will sample 1 random integer from the range 1:(y+1). Since you want a number from 0 to y rather than 1 to y + 1, we subtract 1 at the end.
Also, just pointing out - no need for replace=T here because you are only sampling one value anyway, so it doesn't matter whether it gets replaced or not.
Based on #mathematical.coffee suggestion and my edited example this is the slick final result:
m <- matrix(c(2, 4, 3, 5, 1, 5, 7, 9, 3, 7), nrow=5, ncol=2,)
colnames(m) = c("Y","Z")
m <-data.frame(m)
samp<-function(x){
sample(Z + 1, 1)}
m$randoms <- sapply(m$Z + 1, sample, 1) - 1