I want to have a function where for a particular exceptions it throws and return a message, and then simply check whether what is returned is one of my defined 'exceptions'. For example say I have the function:
divideByX <- function(x){
# If x is NA throws exception
if(is.na(x)){
return(exception('x is NA'))
}
# If x is 0 throws exception
else if(x == 0){
return(exception('Cannot divide by zero'))
}
else{
return(10/x)
}
}
So if x is 0 it returns the expception 'Cannot divide by zero', if x is NA it returns the exception 'x is NA' and for all other values of x it tries to evaluate the expression 10/x.
Then I would want to run something like this:
tempList <- list('a' = 2, 'b' = 0, 'c' = 5, 'd' = NA)
lapply(tempList, function(x){
if(is.exception(x)){
return(x)
}
else{
y <- divideByX(x)
return(y^2)
}
})
So it first checks if the value is one of my defined exceptions and if so returns the message, else it squares my value, so the above should return
$a
[1] 25
$b
[1] 'Cannot divide by zero'
$c
[1] 4
$d
[1] 'x is NA'
Does anyone know the best way to do this? Please let me know if anything is unclear.
Thanks in advance
Create a function to generate exceptions. The exceptions can be a linear hierarchy that extends the simple error class
exception <-
function(class, msg)
{
cond <- simpleError(msg)
class(cond) <- c(class, "MyException", class(cond))
stop(cond)
}
Here's your function
divideByX <- function(x){
# If x is 0 throws exception
if (length(x) != 1) {
exception("NonScalar", "x is not length 1")
} else if (is.na(x)) {
exception("IsNA", "x is NA")
} else if (x == 0) {
exception("DivByZero", "divide by zero")
}
10 / x
}
and use to generate the output you asked for
lapply(tempList, function(x) tryCatch({
divideByX(x)
}, MyException=function(err) {
conditionMessage(err)
}))
or to treat some exceptions differently from others
> lapply(list(NA, 3:5), function(x) tryCatch({
+ divideByX(x)
+ }, IsNA=function(err) {
+ warning(err) # signal a warning, return NA
+ NA
+ }, NonScalar=function(err) {
+ stop(err) # fail
+ }))
Error: x is not length 1
In addition: Warning message:
x is NA
Unless you are always dividing 10, you would want to include the numerator in yoru function.
divideByX <- function(X, num=10) {
if(is.na(X))
return('X is NA')
if(X == 0)
return('Cannot divide by zero')
return(num / X)
}
usage:
y <- 3
lapply(tempList, divideByX, num=y^2)
# $a
# [1] 4.5
#
# $b
# [1] "Cannot divide by zero"
#
# $c
# [1] 1.8
#
# $d
# [1] "X is NA"
Related
Can someone tell me what is wrong with this function in R? The functions can work on a single input, but when I use a vector I get an error:
input_check3 <- function(x){
if (is.finite(x)) {
if (x %% 2 == 0){
print(TRUE)
} else {
print(FALSE)
}
} else {
NA
}
}
data_for_e2 <- c(1, 2, 4, 5, 3)
input_check3(data_for_e2)
#> [1] FALSE
#> Warning messages:
#> 1: In if (is.finite(x)) { : The length of the condition is greater than one, so only its first element can be used
#> 2: In if (x%%2 == 0) { : The length of the condition is greater than one, so only its first element can be used
You could use ifelse, which is a vectorized function:
input_check3 <- function(x){
ifelse(is.finite(x),
x %% 2 == 0, # equiv to ifelse(x %% 2 == 0, TRUE, FALSE), thanks Martin Gal!
NA)
}
Result
[1] FALSE TRUE TRUE FALSE FALSE
I fear I get something really wrong. The basics are from here
and a basic (minimal) example is understood (I think) and working:
fun.default <- function(x) { # you could add further fun.class1 (works)...
print("default")
return(x[1] + x[2])
}
my_fun <- function(x) {
print("my_fun")
print(x)
res <- UseMethod("fun", x)
print(res)
print("END my_fun...")
return(res)
}
x <- c(1, 2)
my_fun(x)
However, if I want to add parameters, something goes really wrong. Form the link above:
Once UseMethod has found the correct method, it’s invoked in a special
way. Rather than creating a new evaluation environment, it uses the
environment of the current function call (the call to the generic), so
any assignments or evaluations that were made before the call to
UseMethod will be accessible to the method.
I tried all variants I could think of:
my_fun_wrong1 <- function(x, y) {
print("my_fun_wrong1")
print(x)
x <- x + y
print(x)
res <- UseMethod("fun", x)
print(res)
print("END my_fun_wrong1...")
return(res)
}
x <- c(1, 2)
# Throws: Error in fun.default(x, y = 2) : unused argument (y = 2)
my_fun_wrong1(x, y = 2)
my_fun_wrong2 <- function(x) {
print("my_fun_wrong2")
print(x)
x <- x + y
print(x)
res <- UseMethod("fun", x)
print(res)
print("END my_fun_wrong2...")
return(res)
}
x <- c(1, 2)
y = 2
# Does not throw an error, but does not give my expetced result "7":
my_fun_wrong2(x) # wrong result!?
rm(y)
my_fun_wrong3 <- function(x, ...) {
print("my_fun_wrong3")
print(x)
x <- x + y
print(x)
res <- UseMethod("fun", x)
print(res)
print("END my_fun_wrong3...")
return(res)
}
x <- c(1, 2)
# Throws: Error in my_fun_wrong3(x, y = 2) : object 'y' not found
my_fun_wrong3(x, y = 2)
Edit after answer G. Grothendieck: Using fun.default <- function(x, ...) I get
Runs after change, but I don't understand the result:
my_fun_wrong1(x, y = 2)
[1] "my_fun_wrong1"
[1] 1 2
[1] 3 4 # Ok
[1] "default"
[1] 3 # I excpect 7
As before - I don't understand the result:
my_fun_wrong2(x) # wrong result!?
[1] "my_fun_wrong2"
[1] 1 2
[1] 3 4 # Ok!
[1] "default"
[1] 3 # 3 + 4 = 7?
Still throws an error:
my_fun_wrong3(x, y = 2)
[1] "my_fun_wrong3"
[1] 1 2
Error in my_fun_wrong3(x, y = 2) : object 'y' not found
I think, this question is really useful!
fun.default needs ... so that the extra argument is matched.
fun.default <- function(x, ...) {
print("default")
return(x[1] + x[2])
}
x <- c(1, 2)
my_fun_wrong1(x, y = 2)
## [1] "my_fun_wrong1"
## [1] 1 2
## [1] 5 6
## [1] 3
Also, any statements after the call to UseMethod in the generic will not be evaluated as UseMethoddoes not return so it is pointless to put code after it in the generic.
Furthermore, you can't redefine the arguments to UseMethod. The arguments are passed on as they came in.
Suggest going over the help file ?UseMethod although admittedly it can be difficult to read.
Regarding the quote from ?UseMethod that was added to the question, this just means that the methods can access local variables defined in the function calling UseMethod. It does not mean that you can redefine arguments. Below ff.default refers to the a defined in ff.
a <- 0
ff <- function(x, ...) { a <- 1; UseMethod("ff") }
ff.default <- function(x, ...) a
ff(3)
## [1] 1
In my script is it possible to get d[[x]] "empty". I tried to do it with else, but it does not work.
How to write else so that it can give a result of checking zero?
for (x in 1:licznik3)
{
if(a[[x]] > d[[x]])
{
out3[[x]] <- wspolne3[[x]]
}
else (a[[x]] < d[[x]])
{
out3[[x]] <- NA
}
}
variables:
> a
[1] 0.1
> d
numeric(0)
> licznik3
[1] 16
Error in d[[x]] : subscript out of bounds
Example:
I have 3 loops.
If a[[x]] is greater than d[[x]]
this value goes to out3
and the next loop checks a similar condition.
My problem is that in the second loop (shown code) d[[x]] can be empty (in the previous loop no value was greater than a[[x]])
Then we have how
> a
[1] 0.1
> d
numeric (0)
Just add additional check that your counter aka licznik3 ;) would not exceed length of vector d. If it exceeds break for-loop.
a <- 1:10
licznik3 <- 7
out3 <- rep_along(a, NA)
wspolne3 <- 2:12
d <- -c(1, 4, 2)
for (x in 1:licznik3) {
if (x > length(d)) {
break
}
if (a[[x]] > d[[x]]) {
out3[[x]] <- wspolne3[[x]]
} else {
out3[[x]] <- NA
}
}
out3
I am trying to write a program that will ask the user for an integer and calculate the integer's factorial and the program will end if the user gives a negative number. I get an
Error in while (x >= 0) { : missing value where TRUE/FALSE
needed and sometimes this
Error in x + 1 : non-numeric argument to binary operator
My code:
x <-readline(prompt="Enter an integer: ")
x <- as.integer(x)
while(x >= 0)
{
y <- factorial(x)
y
x <-readline(prompt="Enter an integer: ")
x <- as.integer(x)
}
Your code will work if you put everything inside a function. I improved your code and created a function myfun.
myfun <- function()
{
z <- TRUE
while( z )
{
x <- readline( prompt="Enter an integer: " )
if ( x < 1 ) {
z <- FALSE
} else {
y <- factorial( as.numeric( x ) )
print( y )
}
}
}
myfun()
# Enter an integer: 1
# [1] 1
# Enter an integer: 5
# [1] 120
# Enter an integer: -1
# >
in a tryCatch function, I would like to don't return NULL or anything when the tryCatch fail.
When you assign to an object an expression which returns an error if the object already exists his value isnt changed, e.g :
> x <- 1
> x
[1] 1
> x <- x + "a"
Error in x + "a" : non-numeric argument to binary operator
> x
[1] 1
And I would like to have the same behaviour using a tryCatch. So in this example after the tryCatch failed "x" is still "1" and not NULL.
f <- function(x){
tryCatch(
expr = {
x <- 1 + x
return(x)
}, error = function(cond){
message("error")
})
}
> x <- f(1)
> x
[1] 2
> x <- f("a")
error
> x
NULL
Use stop do the trick :
f <- function(x){
tryCatch(
expr = {
x <- 1 + x
return(x)
}, error = function(cond){
stop("error")
})
}
> x <- f(1)
> x
[1] 2
> x <- f("a")
Error in value[[3L]](cond) : error
> x
[1] 2
But even if I can modify the 2nd part, stop produces not rly helpful error messages, i.e the 1st part "Error in value[3L] :"
Is there another way to do it ? Thanks.
If you just want stop to not include the beginning part of the error message you just set the call. argument to FALSE.
f <- function(x){
tryCatch(
expr = {
x <- 1 + x
return(x)
}, error = function(cond){
stop("non-numeric argument to binary operator", call.=FALSE)
})
}
x <- 1
x <- f("a")
Error: non-numeric argument to binary operator
x
[1] 1