Command that allows re-checking TRUE/FALSE - r

How to write command (function) that would allow "endless loop" checking whether the internet connection is TRUE else wait and than check again and so on....
Here is attempt what I mean:
havingIP <- function() { if (.Platform$OS.type == "windows") {
ipmessage <- system("ipconfig", intern = TRUE) } else {
ipmessage <- system("ifconfig", intern = TRUE) }
validIP <- "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
any(grep(validIP, ipmessage)) }
The source for the above solution and credit goes here:
How to determine if you have an internet connection in R
if(havingIP()){ source(....) } else { for(i in 1:5) { Sys.sleep(1); cat(i) }}
Something like this but this is not appropriate since I want to execute the command source only once.
while(TRUE){
if(havingIP()){ print("working") } else { for(i in 1:5) { Sys.sleep(1);
cat(i) }}
}
So how to run this without loop that would check every 5sec and if the internet connection is not on wait another 5sec and so on until the internet is on, then execute the source only once and that's it.
Sorry I tried to search for this solution, I'm sure someone has asked something similar but could not find anything since I'm not sure how to search for it anyway. Thanks!

It seems like you might be looking for break:
while (TRUE) {
if (havingIP()) {
print("working") # execute what you want here
break # and if we ever reach here, then exit the while loop
} else {
for (i in 1:5) {
Sys.sleep(1)
cat(i)
}
}
}

A simpler take on lee's answer:
while(!havingIP()) for(i in 1:5) {Sys.sleep(1); cat(i)}
source(...)
This will pause execution until havingIP returns TRUE.

Related

How to redo tryCatch after error in for loop

I am trying to implement tryCatch in a for loop.
The loop is built to download data from a remote server. Sometimes the server no more responds (when the query is big).
I have implemented tryCatch in order to make the loop keeping.
I also have added a sys.sleep() pause if an error occurs in order to wait some minutes before sending next query to the remote server (it works).
The problem is that I don't figure out how to ask the loop to redo the query that failed and lead to a tryCatch error (and to sys.sleep()).
for(i in 1:1000){
tmp <- tryCatch({download_data(list$tool[i])},
error = function(e) {Sys.sleep(800)})
}
Could you give me some hints?
You can do something like this:
for(i in 1:1000){
download_finished <- FALSE
while(!download_finished) {
tmp <- tryCatch({
download_data(list$tool[i])
download_finished <- TRUE
},
error = function(e) {Sys.sleep(800)})
}
}
If you are certain that waiting for 800 seconds always fixes the issue this change should do it.
for(i in 1:1000) {
tmp <- tryCatch({
download_data(list$tool[i])
},
error = function(e) {
Sys.sleep(800)
download_data(list$tool[i])
})
}
A more sophisticated approach could be, to collect the information of which request failed and then rerun the script until all requests succeed.
One way to do this is to use the possibly() function from the purrr package. It would look something like this:
todo <- rep(TRUE, length(list$tool))
res <- list()
while (any(todo)) {
res[todo] <- map(list$tool[todo],
possibly(download_data, otherwise = NA))
todo <- map_lgl(res, ~ is.na(.))
}

How to flush the print buffer in R?

I want to run a long-running simulation and have updates printed periodically. However, I am finding that my print statements are being buffered, even when I explicitly try to flush. Here, for example:
for (i in 1:10)
{
print(i)
flush(stdout())
Sys.sleep(1)
}
I would expect this to increment every 1sec, but it outputs everything at the end, after 10 seconds.
How would you force a flush of the print buffer?
I usually do it like this:
for (i in 1:10) {
message(i,"\r",appendLF=FALSE)
flush.console()
Sys.sleep(1)
}
You can also use cat():
for (i in 1:10) {
# Sleep for 1 second
Sys.sleep(1)
# Print the current iteration
cat(paste0("\r", i))
}

For Next loop - Receiving error

I have tried the following simple for next loop in R programming:
for(i in 1:100) { if(i <= 20) { next } print(i) }
Below is the error message I am receiving:
Error: unexpected symbol in "for(i in 1:100) { if(i <= 20) {next} print"
Please help me understand why I am receiving the error.
Give this a shot:
for (i in 1:100) {
if (i<=20) {
next
};
print(i)
}
Looks like you missed your semi-colon. You need this to denote the end of a statement.
you need to break the line (enter) after {next} and have print(i)} in another line. :) Good Luck

Clean way to wrap-up and handle RMySQL connections?

I'm fairly new to R, so forgive me if this is a amateur question. I still don't get parts of how the R language works and I haven't used closures enough to really build intuition on how to approach this problem.
I want to wrap up opening and closing a database connection in my R project in a clean way. I have a variety of scripts set aside that all use a common DB connection configuration file (I don't put it in my repo, it's a local file only), all of which need to connect to the same MySQL database.
The end goal is to do something like :
query <- db_open()
out <- query("select * from example limit 10")
db_close()
This is what I wrote so far (all my scripts load these functions from another .R file) :
db_open <- function() {
db_close()
db_conn <<- dbConnect(MySQL(), user = db_user, password = db_pass, host = db_host)
query <- function(...) { dbGetQuery(db_conn, ...) }
return(query)
}
db_close <- function() {
result <- tryCatch({
dbDisconnect(db_conn)
}, warning = function(w) {
# ignore
}, error = function(e) {
return(FALSE)
})
return(result)
}
I'm probably thinking of this in an OOP way when I shouldn't be, but sticking db_conn in the global environment feels unnecessary or even wrong.
Is this a reasonable way to accomplish what I want? Is there a better way that I'm missing here?
Any advice is appreciated.
You basically had it, you just need to move the query function into its own function. Regarding keeping db_conn, there really is no reason not to have it in the global environment.
db_open <- function() {
db_close()
db_conn <<- dbConnect(MySQL(), user='root', password='Use14Characters!', dbname='msdb_complex', host='localhost')
}
db_close <- function() {
result <- tryCatch({
dbDisconnect(db_conn)
}, warning = function(w) {
# ignore
}, error = function(e) {
return(FALSE)
})
return(return)
}
query <- function(x,num=-1)
{
q <- dbSendQuery(db_conn, x)
s <- fetch(q, num);
}
Then you should be able to do something like:
query <- db_open()
results <- query("SELECT * FROM msenrollmentlog", 10)
db_close()

Why does R say no loop for break/next, jumping to top level

Why does R throw the error "Error in value[3L] : no loop for break/next, jumping to top level" instead of going to the next iteration of a loop? I'm on R version 2.13.1 (2011-07-08)
for (i in seq(10)) {
tryCatch(stop(), finally=print('whoops'), error=function(e) next)
}
This problem came up because I wanted to create a different image or no image at all when plot failed. The code, using joran's approach, would look like this:
for (i in c(1,2,Inf)) {
fname = paste(sep='', 'f', i, '.png')
png(fname, width=1024, height=768)
rs <- tryCatch(plot(i), error=function(e) NULL)
if (is.null(rs)){
print("I'll create a different picture because of the error.")
}
else{
print(paste('image', fname, 'created'))
dev.off()
next
}
}
Maybe you could try :
for (i in seq(10)) {
flag <- TRUE
tryCatch(stop(), finally=print('whoops'), error=function(e) flag<<-FALSE)
if (!flag) next
}
Unfortunately, once you get inside your error function you're no longer in a loop. There's a way you could hack around this:
for (i in seq(10)) {
delayedAssign("do.next", {next})
tryCatch(stop(), finally=print('whoops'),
error=function(e) force(do.next))
}
Though that is... well, hacky. Perhaps there is a less hacky way, but I don't see one right off.
(This works because delayedAssign happens every loop, canceling out the efforts of force)
EDIT
Or you could use continuations:
for (i in seq(10)) {
callCC(function(do.next) {
tryCatch(stop(), finally=print('whoops'),
error=function(e) do.next(NULL))
# Rest of loop goes here
print("Rest of loop")
})
}
EDIT
As Joris points out, you probably shouldn't actually use either of these, because they're confusing to read. But if you really want to call next in a loop, this is how :).
Wouldn't it make more sense to put the next outside the tryCatch based on an if check? Something like this:
for (i in c(1,2,Inf)) {
rs <- tryCatch(seq(i), finally=print('whoops'), error=function(e) NULL)
if (is.null(rs)){
print("I found an error!")
}
else{
next
}
}
although I'm not sure this is what you want, since I'm a little unclear on what you're trying to do.
EDIT
Based on the OP's revisions, this formulation works for me:
plotFn <- function(fname,i){
png(fname, width=400, height=200)
plot(i)
dev.off()
}
for (i in c(1,Inf,3)) {
fname = paste('f', i, '.png',sep="")
rs <- tryCatch(plotFn(fname,i), error=function(e){dev.off(); return(NULL)})
if (is.null(rs)){
print("I'll create a different picture because of the error.")
}
else{
print(paste('image', fname, 'created'))
next
}
}
I'm certain that not having a dev.off() call in the case of an error needed to be fixed. I'd have to dig a little deeper to figure out exactly why separating png and plot was causing problems. But I think it's probably cleaner to keep the png(); plot(); dev.off() sequence self contained anyway. Also note that I put a dev.off() in the error function.
I haven't tested what will happen if plotFn throws an error on png(), never creates the device and then reaches the error function and calls dev.off(). Behavior may depend on what else you have going on in your R session.

Resources