Converting user input to a number - r

It might be a silly mistake but I'm not able to figure it out.
Here's the sample:
if(K<=50 & k<=K) {
cat("Message A", "\n")
} else {
if(K>50) {
cat("Error A","\n")
return(0)
} else {
cat("Error B","\n")
return(0)
}
}
If I enter K = 9 and k = 2, I still get Error A and the program stops.
Why?
EDIT:
If I take user input for K and k, it gives the "Error A" message. "Error B" works fine. I never get "Message A"
K<-readline("Enter K: ")
k<-readline("Enter k: ")

The reason you're seeing this error is that the readline function returns a string instead of a number. When R compares between a string and a number, it will convert both to a string and compare them alphabetically:
"9" <= 50
# [1] FALSE
"1" <= 50
# [1] TRUE
The solution is to convert the inputted values to the numeric type:
K <- as.numeric(readline("Enter K: "))
k <- as.numeric(readline("Enter k: "))
Note that if you enter something that's not a number then R will store that value as NA; you can check for this with the is.na function.

Related

I want to ask the user to input an integer and check it and return an error message if it isn't in R

now I thought I would simply use is.integer and use the TRUE or FALSE output as a condition for my error message, but it seems even integers give FALSE cause R stores them float or something (e.g. 5) but if I change the input to as.integer then all inputs become integers thus defeating the purpose of the program.
num = readline(prompt = "Enter a number: ")
y = num
x <- is.integer(num)
if (y > 0 && x == FALSE) {
print("Please enter a natural number")
}
readline stores user input as a character. You can use as.numeric() for your case. Input will become NA if it cannot be converted to numeric. Integrality can be tested using round(num) != num.
num <- as.numeric(readline(prompt = "Enter a number: "))
if (is.na(num) | num <= 0 | round(num) != num) {
print("Please enter a natural number")
}

How do I get an "if else" loop in r to save values created within the loop and use them in future runs of the loop?

I am trying to run a simple loop that will count my points. You can see the code is very simple. I think there's something I am missing here about saving the values within loops to objects. Most information I find is for more complex loops. Feels like this should be a simple solution that I just don't understand yet.
test <- function(){
number <- 2
loop <- function(){
entry <- as.numeric(readline(prompt = "Enter Number:"))
if(entry == number){
points <- 2 * points
cat("You have " ,points, " points!", sep ="")
print("Double points!")
}else{
print("Lose a point.")
points <- points - 1
cat("You have " ,points, " points!", sep ="")
if(points > (0)){
loop()
}else{
print("You lose!")
}
}
}
loop()
}
test()
When this runs, user enters 3 and the points become 9 and the loop begins again. If user enters 3 again it should subtract 1 point from 9 to make 8. But the object points value is 9 and will not go less than that.
You should use the current value of points as an input to the loop function. And when you call loop(), if it's not the first call, pass in the current value.
test <- function() {
number <- 2
starting_points <- 10
loop <- function(points) {
entry <- as.numeric(readline(prompt = "Enter Number:"))
if (entry == number) {
points <- 2 * points
cat("You have " , points, " points!", sep = "")
print("Double points!")
} else{
print("Lose a point.")
points <- points - 1
cat("You have " , points, " points!", sep = "")
if (points > (0)) {
loop(points)
} else{
print("You lose!")
}
}
}
loop(points = starting_points)
}
test()
I'd also suggest not mixing cat() and print() - they have different behavior in some cases. (I'd avoid cat() unless you are, e.g., writing to log files or trying to avoid auto-formatting done by print - generally print() or message() is more appropriate.)
### Instead of this:
cat("You have " , points, " points!", sep = "")
## use this:
print(paste0("You have " , points, " points!"))
## or this:
print(sprintf("You have %s points", points))
You didn't assign any value to variable points.

mapply not having same return datatype

It return string once and integer other time
f <- function(a){
if (a > 10)
return("any string")
else
return(a)
}
mapply(f,c(1,20,10))
[1] "1" "any string" "any string"
but I want the return value of the function in original form as first is integer
[1] 1 "any string" "any string"
Why your example is not working? vector in R could contains only one data type. When a few types is provided automatic conversion is applied always to lower level representation - here to a character. A list have to be used to grab different data types.
Solution with Map
f <- function(a){
if(a>10)
return('any string')
else{
return(a)
}
}
Map(f, c(1,20,10))

Multiple if statements within loop in R

I have an R script that retrieves CSV files from a daily email in my outlook and then depending whether the date in email subject is greater than a set date, moves them to a specific folder.
The code is splitting the subject line to extract the date - the position of which can be in one of two places in the string, due to recent changes.
I have an if statement built which can successfully locate the date within the string in either circumstance, but I can't then use a second if statement to see if the output from the first if statement is greater than the sample date.
Below is the code I am trying to execute (I have included data that can be reproduced):
# Test data
testLoop <- c("[EXTERNAL] Test Promo Sessions was executed at 28062019 100005",
"[EXTERNAL] Test Promo Sessions was executed at 29062019 100023",
"Test Promo Sessions was executed at 30062019 100007",
"Test Promo Sessions was executed at 01072019 100043",
"Test Promo Sessions was executed at 02072019 100049",
"Test Promo Sessions was executed at 03072019 100001")
# Example date
todaysDateFormatted2 <- '30062019'
# Loop
for(i in testLoop){
if(if(nchar(i) == 51){
strptime(sapply(strsplit(i, "\\s+"), "[", 7),"%d%m%Y")
} else {
strptime(sapply(strsplit(i, "\\s+"), "[", 8),"%d%m%Y")
} > strptime(todaysDateFormatted2,"%d%m%Y")){
print("greater than - move file")
} else {
print("not greater than - do nothing")
}
}
When attempting the execute this code, I get the following error, however I'm not sure how to interpret it:
[1] "not greater than - do nothing"
[1] "not greater than - do nothing"
Error in if (if (nchar(i) == 51) { :
argument is not interpretable as logical
In addition: Warning message:
In if (if (nchar(i) == 51) { :
the condition has length > 1 and only the first element will be used
There were several flaws in your code. The duplicated if was weird, and you strptime into nowhere if you don't assign it to something, below t. Also you may want to assign the else condition to t. Now you can compare t to todaysDateFormatted2 and print the result for each iteration.
for (i in testLoop) {
if (nchar(i) == 51) {
t <- strptime(sapply(strsplit(i, "\\s+"), "[", 7),"%d%m%Y")
} else {
t <- strptime(sapply(strsplit(i, "\\s+"), "[", 8),"%d%m%Y")
}
if (t > strptime(todaysDateFormatted2,"%d%m%Y")) {
print("greater than - move file")
} else {
print("not greater than - do nothing")
}
}
# [1] "not greater than - do nothing"
# [1] "not greater than - do nothing"
# [1] "not greater than - do nothing"
# [1] "greater than - move file"
# [1] "greater than - move file"
# [1] "greater than - move file"
The code in the OP fails because R does not consistently resolve the inner if() statement to a vector of length 1, which causes the outer if() to fail as described in the OP.
If the intent of the code is to decide whether to move a file based on the date in a file name, a simpler version of the code can accomplish what is desired. Here, we reduce the levels of nesting by using lapply() and saving the output from the original inner if() clause to an object. We then compare the saved object to the object representing today's date and write a message to the R log.
# Test data
testLoop <- c("[EXTERNAL] Test Promo Sessions was executed at 28062019 100005",
"[EXTERNAL] Test Promo Sessions was executed at 29062019 100023",
"Test Promo Sessions was executed at 30062019 100007",
"Test Promo Sessions was executed at 01072019 100043",
"Test Promo Sessions was executed at 02072019 100049",
"Test Promo Sessions was executed at 03072019 100001")
# Example date
todaysDateFormatted2 <- '30062019'
datesProcessed <- lapply(testLoop,function(x){
if(nchar(x) == 51) y <- strptime(sapply(strsplit(x, "\\s+"), "[", 7),"%d%m%Y")
else y <- strptime(sapply(strsplit(x, "\\s+"), "[", 8),"%d%m%Y")
if(y > strptime(todaysDateFormatted2,"%d%m%Y")) message("greater than - move file")
else message("not greater than - do nothing")
y
})
...and the output:
> datesProcessed <- lapply(testLoop,function(x){
+ if(nchar(x) == 51) y <- strptime(sapply(strsplit(x, "\\s+"), "[", 7),"%d%m%Y")
+ else y <- strptime(sapply(strsplit(x, "\\s+"), "[", 8),"%d%m%Y")
+ if(y > strptime(todaysDateFormatted2,"%d%m%Y")) message("greater than - move file")
+ else message("not greater than - do nothing")
+ y
+ })
not greater than - do nothing
not greater than - do nothing
not greater than - do nothing
greater than - move file
greater than - move file
greater than - move file
>

R function; if input is not given, ask for it

I'm trying to write a function in R that takes two inputs as strings. If neither input is set, it asks for the inputs and then continues the function.
Input < - function(j,k){
if ((j==j)&&(k==k)){
j <- readline(prompt="Enter Input 1: ")
k <- readline(prompt="Enter Input 2: ")
Input(j,k)
}else if ((j=="<string here>")&&(k=="<string here>")){
....
}
}
I think the better way to structure your approach would be this, using optional arguments and testing to see if they are non-null before proceeding, though admittedly your posted question is very vague:
Input < - function(j=NA, k=NA) {
if (is.na(j) | is.na(k)){
j <- readline(prompt="Enter Input 1: ")
k <- readline(prompt="Enter Input 2: ")
Input(j, k)
} else if ((j == "<string here>") & (k == "<string here>")) {
....
}
}
Although I personally prefer the is.NA or is.NULL (as in #Forrest 's answer), this is an alternative with missing that might look simpler for someone starting now with R.
Input <- function(j, k) {
if (missing(j) | missing(k)){
j <- readline(prompt="Enter Input 1: ")
k <- readline(prompt="Enter Input 2: ")
Input(j, k)
} else if ((j == "<string here>") & (k == "<string here>")) {
....
}
}
I think it's simplest perhaps to put the readline code as the argument. The force commands force evaluation of that code at that point in the function. I don't think they're necessary but depending what else the function does, you may want to make sure that it's asking for j and k first instead of later; otherwise the code will be evaluated when it first needs to know what j and k are.
Input <- function(j = readline(prompt="Enter Input 1: "),
k = readline(prompt="Enter Input 2: ")) {
force(j)
force(k)
if ((j=="<string here>") && (k=="<string here>")) {
....
}
}

Resources