readline command in R is not executing further programming lines - r

I am fairly new in R programming and want to grab keyboard entry to execute further programming codes. As the code as given here is executed, everything works all good but when the exit is entered the program is terminated and it didn't print y and z.
Could you please advise me how to use readline command in loop and execute other program lines after that loop?
n=1
a=1
y=c()
z=c()
x=""
while(x!="exit"){
x<-readline("Enter your name ")
library(stringr)
if(x!="exit" & str_detect(x,"N")){
y[n]=x
n=n+1
}else{
z[a]=x
a=a+1
}
}
print(y)
print(z)

This code works. I have copied it in a foo.R file as so :
# in "foo.R"
n = 1
a = 1
y = character()
z = character()
x = ""
library(stringr)
while (x!="exit") {
x <- readline("Enter your name\n")
if (x!="exit" & str_detect(x,"N")) {
y[n] = x
n = n+1
} else {
z[a] = x
a = a+1
}
}
print(y)
print(z)
And then, from my R console (with the proper working directory), I can run :
source("foo.R")
# Enter your name
# Bob
# Enter your name
# Nate
# Enter your name
# exit
# [1] "Nate"
# [1] "Bob" "exit"
and it seems to work just fine.

Related

Input in R console

a is more than 1 and b is less than 1000. How do I input in a and b in R console instead of defining in the R script? I have read about the readline function but don't really understand it well.
a <- 3
b <- 4
y <- a*b
y
if((y %% 2) == 0) {
print(paste(y,"is Even"))
} else {
print(paste(y,"is Odd"))
}
You can use readline() function.
Example:
my.name <- readline(prompt="Enter name: ")
my.age <- readline(prompt="Enter age: ")
# convert character into integer
my.age <- as.integer(my.age)
print(paste("Hi,", my.name, "next year you will be", my.age+1, "years old."))
example
By just changing your first two lines using readline and wrapping the entire thing in {} You can combine your script into a clause.
{
a <- as.numeric(readline(prompt = "Enter a: ")) # Read in from console and change to number
b <- as.numeric(readline(prompt = "Enter b: ")) # Read in from console and change to number
y <- a*b
y
if((y %% 2) == 0) {
print(paste(y,"is Even"))
} else {
print(paste(y,"is Odd"))
}
}
This allows you to run the whole thing from top to bottom and take your inputs consecutively. You can also make this into a function.

Money adding program in R

I want to create a program in R that takes integer user input and then adds it to the previous user input. ex. user input(say one day): 10, then (maybe the next day) user input: 15 --> output 25.Ideally this would accept nearly an infinite amount of input. here is what I have so far:
amount_spent <- function(){
i <-1
while(i<10){
n <- readline(prompt="How much did you spend?: ")
i<-i+1
}
print(c(as.integer(n)))
}
amount_spent()
Problems I have with this code are that it only saves the last input value, and it is difficult to control when User is allowed to input. Is there any way to save user input to a data that can be manipulated through readline()?
# 1.R
fname <- "s.data"
if (file.exists(fname)) {
load(fname)
}
if (!exists("s")) {
s <- 0
}
n <- 0
while (TRUE) {
cat ("Enter a number: ")
n <- scan("stdin", double(), n=1, quiet = TRUE)
if (length(n) != 1) {
print("exiting")
break
}
s <- s + as.numeric(n)
cat("Sum=", s, "\n")
save(list=c("s"), file=fname)
}
You should run the script like this: Rscript 1.R
To exit the loop press Ctrl-D in Unix, or Ctrl-Z in Windows.
An R-ish way to do it would be through closures. Here is an example for interactive use (i.e. within an R session).
balance_setup <- function() {
balance <- 0
change_balance <- function () {
n <- readline(prompt = "How much did you spend?: ")
n <- as.numeric(n)
if (!is.na(n))
balance <<- balance + n
balance
}
print_balance <- function() {
balance
}
list(change_balance = change_balance,
print_balance = print_balance)
}
funs <- balance_setup()
change_balance <- funs$change_balance
print_balance <- funs$print_balance
Calling balance_setup creates a variable balanceand two functions that can access it: one for changing the balance, one for printing it. In R, functions can only return a single value, so I bundle both functions together as a list.
change_balance()
## How much did you spend? 5
## [1] 5
change_balance()
## How much did you spend? 5
## [1] 10
print_balance()
## [1] 10
If you want many inputs, use a loop:
repeat{
change_balance()
}
Break the loop with Ctrl-C, Escape or whatever is used on your platform.

Using RStudio "Run" Command Line With The readline() Function

I'm looking into having some user interaction in my code using RStudio. However, I'm running into some issues with the behavior of the command line in conjunction with the readline() function. Here's an example to illustrate my issue:
x <- 2
y <- 2
if (x == 2) { x <- readline("Put your x here: ")
} else { x <- 3 }
if (y == 2) { print("Something.")}
If I highlight this and hit "run" (or ctrl-alt-b at the end) to run line by line in the command line, I run into unexpected behavior shown here in the command line:
> x <- 2
> y <- 2
> if (x == 2) { x <- readline("Put your x here: ")
+ } else { x <- 3 }
Put your x here: if (y == 2) { print("Something.")}
Notice that on line 5, it skips right over the "Put your x here: " prompt (I did not input anything) and continues to the next line. Please do also note, however, when I "source" this code, the issue does not happen and the command line runs as expected (prompts me and waits until I input something).
Overall, this is a minor issue, but for testing purposes, it would be a major help to be able to run my user interaction code without having to source the entire file. Thanks for in advance!

Get all R code which is run when running

Suppose I have a bunch of R code in a script and I want to log all the R code which is run from the .GlobalEnv to a flat file or a database together with the errors and warning messages.
I could write a simple logme function as follows or make it a bit more complex to also fetch the errors by changing options(error = mylogginfunction)
mylogfile <- tempfile()
logme <- function(x){
mode <- "at"
if(!file.exists(mylogfile)){
mode <- "wt"
}
myconn <- file(mylogfile, mode)
writeLines(x, myconn)
close(myconn)
invisible()
}
logme(sprintf("%s: started some yadayada, ", Sys.time()))
x <- 10
x * 7
logme(sprintf("%s: done with yadayada", Sys.time()))
## Get the log
cat(readLines(mylogfile))
The log prints out:
2015-05-14 17:24:31: started some yadayada, 2015-05-14 17:24:31: done with yadayada
But what I would like to have is that the logfile writes down the expressions which were executed without me having to write a wrapper around each statement.
I would like the log to look like.
2015-05-14 17:24:31: started some yadayada, x <- 10, x * 7 2015-05-14 17:24:31: done with yadayada
So my question is, how do I fetch what is being executed by R so that I can store the executed expressions in a log/database. And without having to write a function call before each expression (as in myhandler(x <- 10); myhandler(x * 10)).
Any help on this?
For catching input commands you could use addTaskCallback
mylogfile <- tempfile()
addTaskCallback(
function(...) {
expr <- deparse(as.expression(...)[[1]]) # it could handled better...
cat(expr, file=mylogfile, append=TRUE, sep="\n")
# or cat(sprintf("[%s] %s", Sys.time(), expr),...) if you want timestamps
TRUE
}
,name="logger"
)
x <- 10
x * 7
removeTaskCallback("logger")
Then result is:
cat(readLines(mylogfile), sep="\n")
... addTaskCallback definition ...
x <- 10
x * 7
But what you get is parsed expression, which means that line
x+1;b<-7;b==2
will be logged as
x + 1
b <- 7
b == 2
In addition:
output will not be logged, in particular message or warning shown in console
in case of error logging will not be triggered, so you need separate function to handle it
This is probably to simple to work in every case, but you can try with this:
Define myhandler as:
myhandler <- function(x, file = stdout()) {
expr <- substitute(x)
for(e_line in as.list(expr)) {
cat( file = file, as.character(Sys.time()), capture.output(e_line), "\n")
eval(e_line, envir = parent.frame())
}
}
Use it with your code inside the brackets:
myhandler({
a <- 1
a <- a + 1
print(a)
})
Result:
# 2015-05-14 18:46:34 `{`
# 2015-05-14 18:46:34 a <- 1
# 2015-05-14 18:46:34 a <- a + 1
# 2015-05-14 18:46:34 print(a)
# [1] 2
I confess that I don't really get what "to have the running expressions in the same process available as where the R commands are run" means when we chatted a bit in the comments. However, I expanded what I had in mind. You can create a logGenerator.R file with the following lines:
logGenerator<-function(sourcefile,log) {
..zz <- file(log, open = "at")
sink(..zz)
sink(..zz, type = "message")
on.exit({
sink(type="message")
sink()
close(..zz)
})
..x<-parse(sourcefile)
for (..i in 1:length(..x)) {
cat(as.character(Sys.time()),"\n")
cat(as.character(..x[..i]),"\n")
..y<-eval(..x[..i])
}
}
This function takes as arguments the source file and the log file names. This script will take an R file and will log the time at which each instruction is executed. Then it records the expression on the same log file. Every output directed to the stdout() and the error messages are directed to the log file. You obviously don't have to modify in any way your source file.

User input in R

I am trying to run an R script, using Rscript in Windows command prompt and ask for user's input.
So far, i have found answers on how to implement something similar in R's interactive shell. readline() or scan() doesn't seem to work for the command prompt.
Examples:
I have a polynomial y=cX where X can take more than one values X1,X2,X3 and so on. C variable is know, so what i need in order to calculate the value of y is to ask the user for the Xi values and store them somewhere inside my script.
The script bellow does nothing.
UIinput <- function(){
#Ask for user input
x <- readline(prompt = "Enter X1 value: ")
#Return
return(x)
}
The second example below just prompts the message and then ends.
FUN <- function(x) {
if (missing(x)) {
message("Uhh you forgot to eneter x...\nPlease enter it now.")
x <- readLines(n = 1)
}
x
}
FUN()
Console output:
Uhh you forgot to eneter x...
Please enter it now.
character(0)
Any suggestions?
Thanks in advance
cat("input x: ")
x <- readLines(con="stdin", 1)
cat(x, "\n")

Resources