Is there a way how to check if value exists in R environment and if == TRUE, assign this existing value otherwise assign something else?
In other words, I have nothing in my R right now and I created this if else statement.
test <- if_else(exists("my_value"), my_value, "my value missing, assigning this string")
Result of
exists("my_value")
is:
exists("my_value")
[1] FALSE
But once I run whole code I get this
Error in if_else(exists("my_value"), my_value, "my value missing, assigning this string") :
object 'my_value' not found
if() {} else {} is more suitable for this case:
if(exists("my_value")){
test <- my_value } else {
test <- "my value missing, assigning this string"}
Using dplyr::if_else(condition, true, false, missing = NULL) won't work as it is checking the values for true and false are of the same length, class, type, hence the error.
I am guessing it could be done with if_else, if we manage to make values for true and false of the same class somehow.
Related
I want to test for the existence of a variable that is explicitly passed to a function. The task is proving trickier than I expected. The problem is that I want the default argument to be NULL, and I also want users to be able to explicitly pass a NULL value. But if users instead try to pass a variable that doesn't exist –– for example, if they misspell a variable when calling the function –– it too will be NULL in the function, and in this case, I will want my function to stop with an error.
Here is a simple example. It uses the iris dataset, which has a Species variable but not a species variable. With one exception, described below, the function here does what I want. But it is clunky and it doesn't explicitly test for existence, which worries me. Is there a better way?
data(iris)
myFunc <- function (x = NULL) {
if (!missing(x)) { # if x was explicitly passed by user
xName <- deparse(match.call()$x)
if (xName != 'NULL' && is.null(x)) {
stop("The variable doesn't seem to exist.")
}
else print("x was explicitly passed, and there are no problems.")
}
else print("x was not passed by the user.")
}
myFunc(x = NULL) # "x was explicitly passed, and there are no problems."
myFunc(x = iris$Species) # "x was explicitly passed, and there are no problems."
myFunc(x = iris$species) # "The variable doesn't seem to exist."
y <- iris$species
myFunc(y) # "The variable doesn't seem to exist."
Two further notes:
I would like z <- NULL; myFunc(z) to return "x was explicitly passed, and there are no problems." Instead, it returns an error ("The variable doesn't seem to exist."). I can probably get around this by adding code that checks for the existence of z in the calling environment—something like exists(z, envir = parent.frame()))—but is there a better way?
I would like to use exists() to test for the existence of the x object, but it doesn't seem flexible enough. For example, exists(iris) works, but exists(iris$Species) returns FALSE even though I'd like it to return TRUE for this purpose.
I'm trying to determine if a value is found in the binary search tree.
If it's found, the value is printed. If not, a message is printed saying it wasn't found.
My problem is that even when the value is found, the message is printed saying that it wasn't found.
My result seems to reset even after returning True, and I am confused as to why this is happening... I think it's because I'm calling the function recursively, but I don't know how to fix this problem. Any help would be appreciated, thank you.
def lookUpVal(bst,val,result):
if bst == None:#base case, if the tree is 0, return none
return
elif bst['data'] == val:
print ("value found")
result = True
return result
lookUpVal(bst['left'],val,result)
lookUpVal(bst['right'],val,result)
def main(bst):
print ("Enter the value you want to find")
val = int(input())
result = 0
lookUpVal(bst,stud,result)
if result != True:
print ("Value not found")
The problem is with your result variable, you probably think you are passing by reference, what is actually happening is close to pass-by-value.
Here is an example:
def voo(x):
print('x:',id(x))
x = True
print('x:',id(x))
p = False
print('p:',id(p))
voo(p)
print('value of p:',p)
print('p:',id(p))
'id' returns a unique id for any object, including of course boolean ones.
Here's the output: (numbers will vary in your pc)
p: 1613433952
x: 1613433952
x: 1613433936
value of p: False
p: 1613433952
First note, False in output, p's value has not changed. But to see why that's happening, closely examine the id values, specially how x's id changed after assignment in function; which means python allocated a new object. And old one is still referenced by 'p', as evident in it's output, which has not changed.
I'm working my way through the Data Science courses at DataCamp. (Not a plug.) One of the practice lessons has the following completed solution:
# logs is available in your workspace
extract_info <- function(x, property = "success", include_all = TRUE) {
info <- c()
for (log in x) {
if (include_all || !log$success) {
info <- c(info, log[[property]])
}
}
return(info)
}
# Call extract_info() on logs, no additional arguments
extract_info(logs)
# Call extract_info() on logs, set include_all to FALSE
extract_info(logs, include_all = FALSE)
The first call (extract_info(logs)) works as I would expect it to: it returns a vector containing all the log entries (regardless of the value of log$success).
The second call (extract_info(logs, include_all = FALSE)) does not return the results I would expect. It returns a vector containing only those results where log$success evaluates to FALSE.
It seems to me that the use of the || operator should cause the if block to short-circuit, and the second call should return nothing. From what I can tell, R evaluates expressions from left to right; but this looks like it's evaluating from right to left.
Can someone explain what's going on here?
(According to the site, this is the correct solution, and there's nothing wrong with the code. I want to know why it works the way it does. Even if the answer is that I'm overlooking something painfully obvious and stupid.)
Well || is the "or" operator. You don't short circuit the "or" operator with a FALSE value; you basically ignore that parameter and just look at the next one because you are looking for any TRUE value.
Assume a is a boolean value. These should be equivalent (<==>).
# or
FALSE || a <==> a
TRUE || a <==> TRUE
# and
TRUE && a <==> a
FALSE && a <==> FALSE
It seems like this was a temporary confusion.
|| is OR and so if either condition evaluates to TRUE, the compound expression evaluates to TRUE. If include_all was TRUE, you could short-circuit the expression, but when include_all is FALSE, you must wait to see what the other part is.
I want to return my error message if arguments passed to the function are not of the required type (character)
if (!typeof(param1) == "character" || !typeof(param2) == "character") {
stop("You must provide valid arguments")
}
This only works if I provide invalid arguments. How can I ensure the message is displayed if some of the parameters are missing, because if doesn't work if I call the function without any parameters ?
You can use missing() to check whether an argument is provided. This is very much preferred over the other answers that suggest using default values that are of a different type than what expected (how confusing!). Only use defaults when it makes sense to have a default.
Also, it is not a good idea to use typeof() for type checking, in general. The typeof() function returns how the data are stored in the R implementation. Usually, a function cares whether an object presents a particular API, which corresponds to the class. To check inheritance, use is(). But in this case, for both readability and just to follow conventions, consider using is.character().
So you might have something like:
if (missing(param1) || !is.character(param1)) {
stop("'param1' must be provided as a character vector")
}
Also, things to keep in mind when checking vectors:
Often we really are expecting a scalar, i.e., a length-one vector, but a vector can have arbitrary length, so we should check that it is of length one.
Vectors can contain missing values, which code often cannot handle, so we often need to ensure that the values are not missing.
You might find it useful to define helpers for this, such as this function from the S4Vectors package in Bioconductor:
isSingleString <- function (x)
{
is.character(x) && length(x) == 1L && !is.na(x)
}
Then:
if (missing(param1) || !isSingleString(param1)) {
stop("param1 must be a single, non-NA string")
}
To ensure not to have problms with misisng parameters, you should provide default arguments.
Use stopifnot, it is designed to check arguments.
here how I would do this:
func_check <-
function(param1="",param2=""){
stopifnot(typeof(param1) == "character",
typeof(param2) == "character")
}
## param2 is numeric
func_check(param1= 'a',param2=2)
## param2 is missing
func_check(param1= 1)
EDIT
In case you want to check for missing values , toy shoudl use dotted parameters. Then you can deal it with using the match.call. Here an example where I test for missings and not valid parameters.
func_check <-
function(...){
ll <- as.list((match.call()[-1]))
stopifnot(c('param1','param2' )%in% names(ll))
param1 = ll$param1
param2 = ll$param2
stopifnot(typeof(param1) == "character",
typeof(param2) == "character")
}
func_check(param1= 'a',param2=2)
If I define the following function:
myfunc <- function(param1, param2, numeric1, param3) {
if (!is.character(param1) || !is.character(param2)) {
stop("You must provide valid arguments for param1 and param2")
} else if(!is.numeric(numeric1)) {
stop("Please provide numeric input")
} else if(!is.character(param3)){
stop("Please provide character input for param3")
}
#some code here for your function, e.g.
paste0(param1, param2, numeric1, param3)
}
It throws an error whenever I don't give it 4 input parameters in the call of myfunc, including if I call it without any arguments (so the error occurs both if aguments are missing and when they are not of the correct type). Is that different from what you are looking for?
my R code ends up containing plethora of statements of the form:
if (!is.null(aVariable)) {
do whatever
}
But this kind of statement is hard to read because it contains two negations. I would prefer something like:
if (is.defined(aVariable)) {
do whatever
}
Does a is.defined type function that does the opposite of !is.null exist standard in R?
cheers,
yannick
You may be better off working out what value type your function or code accepts, and asking for that:
if (is.integer(aVariable))
{
do whatever
}
This may be an improvement over isnull, because it provides type checking. On the other hand, it may reduce the genericity of your code.
Alternatively, just make the function you want:
is.defined = function(x)!is.null(x)
If it's just a matter of easy reading, you could always define your own function :
is.not.null <- function(x) !is.null(x)
So you can use it all along your program.
is.not.null(3)
is.not.null(NULL)
Ian put this in the comment, but I think it's a good answer:
if (exists("aVariable"))
{
do whatever
}
note that the variable name is quoted.
I have also seen:
if(length(obj)) {
# do this if object has length
# NULL has no length
}
I don't think it's great though. Because some vectors can be of length 0. character(0), logical(0), integer(0) and that might be treated as a NULL instead of an error.
To handle undefined variables as well as nulls, you can use substitute with deparse:
nullSafe <- function(x) {
if (!exists(deparse(substitute(x))) || is.null(x)) {
return(NA)
} else {
return(x)
}
}
nullSafe(my.nonexistent.var)
The shiny package provides the convenient functions validate() and need() for checking that variables are both available and valid. need() evaluates an expression. If the expression is not valid, then an error message is returned. If the expression is valid, NULL is returned. One can use this to check if a variable is valid. See ?need for more information.
I suggest defining a function like this:
is.valid <- function(x) {
require(shiny)
is.null(need(x, message = FALSE))
}
This function is.valid() will return FALSE if x is FALSE, NULL, NA, NaN, an empty string "", an empty atomic vector, a vector containing only missing values, a logical vector containing only FALSE, or an object of class try-error. In all other cases, it returns TRUE.
That means, need() (and is.valid()) covers a really broad range of failure cases. Instead of writing:
if (!is.null(x) && !is.na(x) && !is.nan(x)) {
...
}
one can write simply:
if (is.valid(x)) {
...
}
With the check for class try-error, it can even be used in conjunction with a try() block to silently catch errors: (see https://csgillespie.github.io/efficientR/programming.html#communicating-with-the-user)
bad = try(1 + "1", silent = TRUE)
if (is.valid(bad)) {
...
}