Reset Loop Variable in R - r

I am looping through a variable "i" in a for loop and want to reassign a value to "i" based on the outcome of an if statement. Example below.
for (i in 1:nrow(df)) {
if (df[i, 5] > 4) {
i <- 1
} else {
df[i, 5] <- df[1, 5] - 1
}
}
The script works as expected if I manually run it multiple times, but it doesn't seem to be reassigning i correctly and/or registering it in the loop. Ideas? Suggestions? Thanks in advance!

Changing the value of i inside the loop won't change where you are in the 1:nrow(df). I think this illustrates nicely:
counter = 1
for (i in 1:3) {
cat("counter ", counter, "\n")
cat("i starts as ", i, "\n")
i = 7
cat("i is is set to ", i, "\n\n")
counter = counter + 1
}
# counter 1
# i starts as 1
# i is is set to 7
#
# counter 2
# i starts as 2
# i is is set to 7
#
# counter 3
# i starts as 3
# i is is set to 7
Maybe you should be using a while loop? I think this is what you are trying to achieve, but with no sample input, explanation, or desired output provided in your question, it's just a guess:
i <- 1
while (i <= nrow(df)) {
if (df[i, 5] > 4) {
i <- 1
} else {
df[i, 5] <- df[1, 5] - 1
i <- i + 1
}
}

Related

R Floop behavior

Suppose I have the following R loop:
for(i in 1:5){
print(i)
i = i + 1
}
This produces the following result:
1
2
3
4
5
Which is weird since I did redefine the index inside the loop.
Why do we see this behavior?
I thought I would see something like the following:
1
3
4
5
6
Assignment to the looping variable i is discarded on the next loop iteration, so i = i + 1 has no effect. If you want to change the value of i within the loop, you can use a while loop.
However, your intended output of 1 3 4 5 6 doesn't make sense for a couple of reasons:
assignment of i, as already mentioned;
why does it not increment every other loop?; and
the domain of i, 1:5, is locked in at the first pass of the loop.
Having said that, try this:
i <- 1
lim <- 5
while (i <= lim) {
if (i == 2) {
lim <- lim + 1
} else {
print(i)
}
i <- i + 1
}
# [1] 1
# [1] 3
# [1] 4
# [1] 5
# [1] 6
(My only caution here is that if your increment of i is conditional on anything, there needs to be something else that prevents this from being an infinite loop. Perhaps this caution is unnecessary in your use-case, but it seems relevant to at least mention it.)
The i is the for each value and that cannot be modified with i = i + 1. We may use an if condition
for(i in 1:5){
if(i != 2)
print(i)
}
-output
[1] 1
[1] 3
[1] 4
[1] 5
Also, if the intention is to subset a vector, why not use vectorized option
v1 <- 1:5
v1[v1 != 2]

Find Previous Prime Number using R

I am trying to find Previous Prime number of given value. The mentioned code works fine if I pass prime Number straight away as input lp(7) returns 7. But if I pass lp(6) none are displaying. I am expecting 5 to return.
How do I find the previous prime Number for given one.
Suggestions / Corrections are much appreciated
lp <- function(x){
temp <- x:2
while (x == 2L || all(x %% 2L:max(2,floor(sqrt(x))) != 0))
{
return(x)
}
}
If you run this function a lot of times, probably most efficient is to generate a list of primes once, and search where your value lies in that sequence
library(primes)
primes = generate_primes(2, 1e6)
find_lower_prime = function(x) {
primes[findInterval(x, primes)]
}
find_lower_prime(6)
# [1] 5
You can use the following
lp <- function(x){
previousNumbers <- 2:x
previousPrimes <- sapply(previousNumbers, function(num) {
divisorsToCheck <- 2:max(2,floor(sqrt(num)))
if(num == 2 | all(num %% divisorsToCheck != 0)) {
return(num)
} else {
return(NA)
}
})
previousPrimes[!is.na(previousPrimes)]
}
to get all previous primes.
lp(18) # 2 3 5 7 11 13 17
lp(5) #2 3 5
You can try the code lie below
lp <- function(x) {
p <- x - 1
repeat {
if (p %in% c(2, 3) | all(p %% ceiling(sqrt(2:p)) != 0)) {
return(p)
}
p <- p - 1
}
}
and you will see
> lp(5)
[1] 3
> lp(6)
[1] 5
> lp(7)
[1] 5
> lp(8)
[1] 7
> lp(11)
[1] 7
Hi All this worked for me ..
lp <- function(x){
for(i in x:2)
{
while (i == 2L || all(i %% 2L:max(2,floor(sqrt(i))) != 0))
{
return(i)
}
}
}

About missing value where TRUE/FALSE needed in R

I want to return the number of times in string vector v that the element at the next successive index has more characters than the current index.
Here's my code
BiggerPairs <- function (v) {
numberOfTimes <- 0
for (i in 1:length(v)) {
if((nchar(v[i+1])) > (nchar(v[i]))) {
numberOfTimes <- numberOfTimes + 1
}
}
return(numberOfTimes)
}
}
missing value where TRUE/FALSE needed.
I do not know why this happens.
The error you are getting is saying that your code is trying to evaluate a missing value (NA) where it expects a number. There are likely one of two reasons for this.
You have NA's in your vector v (I suspect this is not the actual issue)
The loop you wrote is from 1:length(v), however, on the last iteration, this will try the loop to try to compare v[n+1] > v[n]. There is no v[n+1], thus this is a missing value and you get an error.
To remove NAs, try the following code:
v <- na.omit(v)
To improve your loop, try the following code:
for(i in 1:(length(v) -1)) {
if(nchar(v[i + 1]) > nchar(v[i])) {
numberOfTimes <- numberOfTimes + 1
}
}
Here is some example dummy code.
# create random 15 numbers
set.seed(1)
v <- rnorm(15)
# accessing the 16th element produces an NA
v[16]
#[1] NA
# if we add an NA and try to do a comparison, we get an error
v[10] <- NA
v[10] > v[9]
#[1] NA
# if we remove NAs and limit our loop to N-1, we should get a fair comparison
v <- na.omit(v)
numberOfTimes <- 0
for(i in 1:(length(v) -1)) {
if(nchar(v[i + 1]) > nchar(v[i])) {
numberOfTimes <- numberOfTimes + 1
}
}
numberOfTimes
#[1] 5
Is this what you're after? I don't think there is any need for a for loop.
I'm generating some sample data, since you don't provide any.
# Generate some sample data
set.seed(2017);
v <- sapply(sample(30, 10), function(x)
paste(sample(letters, x, replace = T), collapse = ""))
v;
#[1] "raalmkksyvqjytfxqibgwaifxqdc" "enopfcznbrutnwjq"
#[3] "thfzoxgjptsmec" "qrzrdwzj"
#[5] "knkydwnxgfdejcwqnovdv" "fxexzbfpampbadbyeypk"
#[7] "c" "jiukokceniv"
#[9] "qpfifsftlflxwgfhfbzzszl" "foltth"
The following vector marks the positions with 1 in v where entries have more characters than the previous entry.
# The following vector has the same length as v and
# returns 1 at the index position i where
# nchar(v[i]) > nchar(v[i-1])
idx <- c(0, diff(nchar(v)) > 0);
idx;
# [1] 0 0 0 0 1 0 0 1 1 0
If you're just interested in whether there is any entry with more characters than the previous entry, you can do this:
# If you just want to test if there is any position where
# nchar(v[i+1]) > nchar(v[i]) you can do
any(idx == 1);
#[1] TRUE
Or count the number of occurrences:
sum(idx);
#[1] 3

switch case: several equivalent cases expressions in r

In r-programming:
i want to use the same method to handle cases 1 and 10, ie, when the loop is in round 1 and then in 10 again. same for 2 and 11.
is there a way to have several case expressions being handled by the same method
for k == 1 and later also fo 10 it should use the first case and for k ==2 and later 11 it should use the second case. the above code doesn't work.
for(i in 1:x) {
switch(k,
"1", "10"= {
correct <- test[21,1]
current <- test[i-p,1]
if(all(correct == current)){
answers[i-p,k] <- c(1)
} else{
answers[i-p,k] <- c(0)
}
},
"2","11" ={
correct <- test[21,2]
current <- test[i,2]
if(all(correct == current)){
answers[i,k] <- c(1)
} else{
answers[i,k] <- c(0)
}
}
}
the same code for only one case expression works:
for(i in 1:x) {
switch(k,
"1" = {
correct <- test[21,1]
current <- test[i-p,1]
if(all(correct == current)){
answers[i-p,k] <- c(1)
} else{
answers[i-p,k] <- c(0)
}
},
"2" ={
correct <- test[21,2]
current <- test[i,2]
if(all(correct == current)){
answers[i,k] <- c(1)
} else{
answers[i,k] <- c(0)
}
}
}
in java we can use case 1 : case 2 to do that. how is it done in r?
i appreciate your help. alternatively i could also copy the code but don't want to if i can avoid it.
My personal choice would be to remap your k to the overlapping cases. Example:
k<-1:20
kmatch<-(k-1)%%9 +1
# [1] 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2
Then feed kmatch to your case expression
The syntax is along the lines of
f = function(x)
switch(x, "1"=, "10"="first", "11"="eleventh", "none")
Note the equal sign after each named expression, other than the default value.
> f("1")
[1] "first"
> f("10")
[1] "first"
> f("11")
[1] "eleventh"
> f("12")
[1] "none"
This is documented in the third paragraph of the 'Details' section of ?switch.

multiple next statements in function

I'm trying to run a function much more complex but equal to:
A <<- 5
B <<- 5
table <- data.frame(A,B)
backup <- table
test <- function(A,B){
while(A > 0){
r <- runif(1,0,1)
if ((r >= 0)&(r <= 0.5)){
A <- A + 1
B <- B - 1
} else if ((r > 0.5)&(r<=1)){
A <- A - 1
B <- B + 1
}
tab <- cbind(A,B)
table <<- rbind(table,tab)
if (nrow(table) == 10) {
break
} else if ((A > 0) & (nrow(table) != 10)) {
next
} else {if ((A == 0) & (nrow(table != 10)) { #pointing to error here?
A <- 5
B <- 5
table <- backup
next
}
}
}
So what I want this function to do is stop when the when number of rows of the table (= the number of times the function ran) is equal to a certain value, in this case 10. But A cannot take a value below 0. If A reaches 0 before the number of rows of the table is 10 the whole process has to start again, with the same inputvalues as before.
However, this function does not work. I think it's because I use multiple next statements, is that correct?
Thanks!
I think you're on the right track... just a few recommendations
I think this accomplishes what you're trying to achieve a little cleaner. I second Carl's suggestion of avoiding the global operator '<<-' when possible and passing the objects through to the function as arguments or parameters. I also second Justin's suggestion of avoiding the break command in favor of placing the return() call smartly. To accomplish this, I put your 10 (stopping criteria) directly into the while loop. I included it as a parameter n so that you can experiment with different stopping criteria. Hope this helps :)
test <- function(A,B,n){
A0 <- A
B0 <- B
tab <- data.frame(A,B)
while(A > 0 & nrow(tab) < n){
r <- runif(1,0,1)
if (r <= 0.5){
A <- A + 1
B <- B - 1
} else {
A <- A - 1
B <- B + 1
}
tab1 <- cbind(A,B)
tab <- rbind(tab,tab1)
if(nrow(tab)<n & A==0){
A<-5
B<-5
tab <- cbind(A0,B0)
names(tab) <- c('A', 'B')
print(paste('found A==0 in less than ', n, ' iterations', sep=''))
}
}
return(tab)
}
Testing function...
## running function
A <- 5
B <- 5
testDF <- test(A,B,10)
> testDF
A B
1 5 5
2 6 4
3 5 5
4 6 4
5 7 3
6 8 2
7 9 1
8 10 0
9 9 1
10 10 0

Resources