So I am suppose to Use && and/or || and reprogram the NthRoot function. The NthRoot Function code is this:
NthRoot<-function(m,n) {
if(!is.integer(n)!=1) {
stop("Error: N must have length 1. Go away.")
}
else if (!is.integer(n) | is.numeric(n)) {
return(m^1/n)
}
else
stop('Error: You must input an interger or vector of intergers.
Existing...\n\n')}
When I replace if and else if, with double & and double |, I receive an error message, Error: unexpected '&&' in:
"NthRoot<-function(m,n) {
&&". I am having a hard time understanding this part of R programming so I'm struggling a lot. Any help is greatly appreciated. Thank you
Related
I have a value that can be NULL or a string. The second test fails because a is of length 0.
How do I write an if-statement that handles both cases?
Example:
a <- NULL
if (is.null(a) | a=="something else then null") {
print("test")
}
is.null(a) || a=="something else then null"
(similarly, use && instead of & in a situation like this)
Explanation: when you use |, all conditions are checked one by one and then the "or" assertion is applied. This means that if one of the conditions is invalid, then there is an error, like in your case.
When you use ||, the "or" assertion is checked after each condition check. In your case, is.null(a) is TRUE. This means that is.null(a) "or" any other condition will also be TRUE, so there's no need to check the other condition.
This is based on my understanding of how it works, it's not a definition coming from the docs. I hope it's clearer.
More info: What's the differences between & and &&, | and || in R?
I want to check if a variable is '' or 'NULL'. I did below:
x =NULL #or ''
if(is.null(x) || x=='') {
print('nothing')
} else {
print(x)
}
My question is what is the best way to check this condition? I feel like there is some better way to do this...
Rather than check if it is NULL or an empty character string it might make more sense to check if it has a non-zero length and is a string which is not empty. Then the first leg of the if will handle the primary case and the else leg will handle the less common case which seems easier to follow than the other way around.
if (length(x) && nzchar(x)) x else NA
Good day,
I am a beginner and trying to understand why I am getting the error below.
I am trying to create a function that would return 0 or 1 based on column values in data set.
LT = function(Lost.time) {
For (i in 1:dim(df)) {
if (df$Lost.time > 0) {
x = 1
}
else {
x = 0
}
return(x)
}
}
Error: no function to return from, jumping to top level In addition: Warning
message: In if (df$Lost.time > 0) { : the condition has length > 1 and only
the first element will be used> } Error: unexpected '}' in "}"
There are a couple of mistakes in the code:
R is case sensitive. Use for instead of For.
If you are looping over the entries in df$Lost.time, the individual elements should be addressed within the loop using df$Lost.time[i]. However, a loop is not necessary for this task.
An else statement should not begin on a new line of the code. The parser cannot know that the if statement is not finished after the first block. If the else statement is enclosed in curly braces like in } else { there will be no problem in this sense.
The parameter passed to the function is not suitable. Maybe you could pass df, instead of Lost.time, but it may be necessary to rewrite parts of the function.
The use of 1:dim(df) in the for loop should work, but it will trigger a warning message. It is better to use 1:nrow(df).
Those are syntax problems. However, the main issue is probably what has been addressed in the answer by #TimBiegeleisen: In the loop you are checking for each of the ̀nrow(df) elements of df$Lost.time whether a specific condition is fulfilled. It therefore does not seem to make sense to have a single binary result as return value. The purpose of the function should be clarified before it is implemented.
An alternative to this function could be constructed in a one-liner with ifelse.
It is not clear what you actually want to return in your function. return can only be called once, after which it will return a single value and the function will terminate.
If you want to get a vector which will contain 1 or 0 depending on whether a given row in your data frame has Lost.time > 0, then the following one liner should do the trick:
x <- as.numeric(df$Lost.time > 0)
If loops are used for writing a function indices should be used for each element.
Create a variable(x) in your dataframe, if the statements goes true it prints 1 else 0
LT = function(Lost.time) {
for (i in 1:dim(df)) {
if (as.numeric(df$Lost.time[i]) > 0) {
df$x[i] <- 1
}else{
df$x[i] <- 0
}
}
}
I write my if {...} else {...} statement in R in the following way as I find it more readable.
Testifelse = function(number1)
{
if(number1>1 & number1<=5)
{
number1 =1
}
else if ((number1>5 & number1 < 10))
{
number1 =2
}
else
{
number1 =3
}
return(number1)
}
According to ?Control:
... In particular, you should not have a newline between } and else to avoid a syntax error in entering a if ... else construct at the keyboard or via source ...
the function above will cause syntax error, but actually it works! What's going on here?
Thanks for your help.
Original question and answer
If we put in R console:
if (1 > 0) {
cat("1\n");
}
else {
cat("0\n");
}
why does it not work?
R is an interpreted language, so R code is parsed line by line. (Remark by #JohnColeman: This judgement is too broad. Any modern interpreter does some parsing, and an interpreted language like Python has no problem analogous to R's problem here. It is a design decision that the makers of R made, but it wasn't a decision that was forced on them in virtue of the fact that it is interpreted (though doubtless it made the interpreter somewhat easier to write).)
Since
if (1 > 0) {
cat("1\n");
}
makes a complete, legal statement, the parser will treat it as a complete code block. Then, the following
else {
cat("0\n");
}
will run into error, as it is seen as a new code block, while there is no control statement starting with else.
Therefore, we really should do:
if (1 > 0) {
cat("1\n");
} else {
cat("0\n");
}
so that the parser will have no difficulty in identifying them as a whole block.
In compiled language like C, there is no such issue. Because at compilation time, the compiler can "see" all lines of your code.
Final update related to what's going on inside a function
There is really no magic here! The key is the use of {} to manually indicate a code block. We all know that in R,
{statement_1; statement_2; ...; statement_n;}
is treated as a single expression, whose value is statement_n.
Now, let's do:
{
if (1 > 0) {
cat("1\n");
}
else {
cat("0\n");
}
}
It works and prints 1.
Here, the outer {} is a hint to the parser that everything inside is a single expression, so parsing and interpreting should not terminate till reaching the final }. This is exactly what happens in a function, as a function body has {}.
As a follow-up to my previous question on the usage of && and || in if statements, I am wondering whether there is any drawback to replacing && and || by purely scalar operators in my own package. These should produce exactly the same results as their base counterparts, except that they throw error messages when applied to arguments of length > 1. In particular, they do short-circuiting.
`&&` <- function(x, y) {
if (!x[1]) {
stopifnot(length(x) == 1)
return(FALSE)
}
stopifnot(length(x) == 1)
if (!y[1]) {
stopifnot(length(y) == 1)
return(FALSE)
}
stopifnot(length(y) == 1)
TRUE
}
`||` <- function(x, y) {
if (x[1]) {
stopifnot(length(x) == 1)
return(TRUE)
}
stopifnot(length(x) == 1)
if (y[1]) {
stopifnot(length(y) == 1)
return(TRUE)
}
stopifnot(length(y) == 1)
FALSE
}
Is it safe to do these replacements in a package? Or might that break something? (Except functions that actually rely on the vectorised behavior, obviously...)
Note that I do not plan to export these functions; they are only for internal use in my package.
If I understand it correctly, these replacements should then only affect my own functions. They can't affect anything outside of my package, right?
No. You might be able to make it safe for the computer, but code needs to be safe for the reader too. Someday you'll want to share this code with others, or you'll come back to it yourself after a time away, and this kind of overloading will be confusing. Better by far to use a new function name.
Also, you'll need to be very careful about how your functions handle NA and NULL values. Your current version has different behaviors than the usual ones for NA, and possibly for NULL; I didn't do a full check. I was surprised to notice, though, that when one of the inputs is NULL, order matters for the standard R versions.
EDIT: This issue with NA values is something to think hard about, and possibly another reason to not just write a single function intended to replace && and ||. For flow control, you need either TRUE or FALSE, NA will throw an error. So should TRUE && NA throw an error? Or be FALSE? Or even TRUE? It may depend, and doing the usual thing of if(!is.na(x) && x) or if(any(is.na(x))) may offer more flexibility and clarity to the reader.
If I were to proceed, my preference would be to think of your new versions as scalar versions of all and any and name them accordingly, to be used like scalar.all(a, b) instead of a && b. Or perhaps if you're thinking about it from the flow control perspective, add a parameter to describe what to do with NA values, flowcontrol.all(a, b, na=c("error", "TRUE", "FALSE").
By the way, I applaud your efforts, in general. Being aware of these issues and writing code to be safe about them seems like a good idea. However, after thinking about this more and trying briefly to write my own versions, I feel that within your own package it would be preferable to do this as needed on a case by case basis. There are times when you'll know as a package writer that one or both of the inputs can only be a scalar, and then this extra code is unnecessary.
Still, here's an attempt at a scalar.all function.
scalar.all <- function(...) {
ns <- eval(substitute(alist(...)))
sofar <- TRUE
for(n in ns) {
x <- eval(n)
if (length(x) != 1L) {
stop(paste(list(n)), " is not a scalar with length 1")
}
if (is.na(x)) sofar <- NA
else if (!x) return(FALSE)
}
sofar
}