askYesNo no found function
I am trying to eliminate some columns through askYesNo but the function at the end does not execute me when the value is true, can you help me
emp.data <- data.frame(
emp_id = c (1:5),
emp_name = c("Rick","Dan","Michelle","Ryan","Gary"),
salary = c(623.3,515.2,611.0,729.0,843.25),
start_date = as.Date(c("2012-01-01", "2013-09-23", "2014-11-15", "2014-05-11",
"2015-03-27")),
stringsAsFactors = FALSE
)
date_Na = list("emp_name")
Delete<- function(){
Answer = askYesNo("you want to remove the columns")
if (Answer == "TRUE" ) emp.data <- emp.data[ ,-which(names(emp.data) %in% date_Na)]
else print("Columns are not deleted")
}
when executing the function it does not delete the emp_name column
Solution 1:
Up front: the issue is due to Invisibility.
A few things:
-
The return value from
askYesNo
is alogical
, so== "TRUE"
is just overkill and doing silent coercion from a logical tocharacter
. You can just doif (Answer) ...
. -
Since the result can be
NA
(if "canceled"), then your conditional will fail if the user cancels. In that case, you really should be explicitly checking forNA
values as well withif (!is.na(Answer) && Answer) ...
. -
Regardless, your function is returning value, it's just doing it invisibly. You can do one of three things:
-
If you want to see it and not change the default "invisible" behavior, wrap it in
(..)
:Delete() # you want to remove the columns (Yes/no/cancel) Yes (Delete()) # you want to remove the columns (Yes/no/cancel) Yes # emp_id salary start_date # 1 1 623.30 2012-01-01 # 2 2 515.20 2013-09-23 # 3 3 611.00 2014-11-15 # 4 4 729.00 2014-05-11 # 5 5 843.25 2015-03-27
The
(..)
forces it to be visible. -
You can assign it to a variable and look at that variable itself,
ret <- Delete() # you want to remove the columns (Yes/no/cancel) yes ret # emp_id salary start_date # 1 1 623.30 2012-01-01 # 2 2 515.20 2013-09-23 # 3 3 611.00 2014-11-15 # 4 4 729.00 2014-05-11 # 5 5 843.25 2015-03-27
-
You can explicitly return thedata (see function definitions below) from the function, in which case it will "never" be invisible.
Delete() # you want to remove the columns (Yes/no/cancel) yes # emp_id salary start_date # 1 1 623.30 2012-01-01 # 2 2 515.20 2013-09-23 # 3 3 611.00 2014-11-15 # 4 4 729.00 2014-05-11 # 5 5 843.25 2015-03-27
-
-
BTW, if the user selects "no", the data is not returned at all, even invisibly. Why is this? Because your function does not explicitly return the data. When there is no explicit
return(.)
statement, then a function returns the value of the last expression evaluated. In the case of a "no", this isprint
, which is just going to print and then return the (same) string:(Delete()) # you want to remove the columns (Yes/no/cancel) no # [1] "Columns are not deleted" # this is printed from the function # [1] "Columns are not deleted" # this is the return value from print, ergo the return value from the function
(To see that
print
returns its string, use my(..)
trick onprint
, which normally returns the string invisibly.print("hello")
versus(print("hello"))
.) -
Defensively, however, if no columns are found from
date_NA
, then your function is going to return nothing, which is counter-intuitive, it should return everything. For demonstration,date_Na <- "FOO" # obviously not going to be found here Delete() # you want to remove the columns (Yes/no/cancel) yes # data frame with 0 columns and 5 rows
The fix is to not use
which
: negation of%in%
will return a logical vector and always work here.Delete <- function() { Answer = askYesNo("you want to remove the columns") if (!is.na(Answer) && Answer) emp.data <- emp.data[ ,!names(emp.data) %in% date_Na] else print("Columns are not deleted") emp.data # return(emp.data) is what we "think" here, but 'return' is rarely necessary/beneficial } Delete() # you want to remove the columns (Yes/no/cancel) yes # emp_id emp_name salary start_date # 1 1 Rick 623.30 2012-01-01 # 2 2 Dan 515.20 2013-09-23 # 3 3 Michelle 611.00 2014-11-15 # 4 4 Ryan 729.00 2014-05-11 # 5 5 Gary 843.25 2015-03-27
-
Perhaps a tangent, but ... it's generally a bad idea to have a function rely on the presence of variables outside of its scope. You can always assign defaults to function arguments. I would recommend a function definition more along the lines of this, where the user can override the data:
Delete <- function(dat = emp.data, date_na = "emp_name") { Answer = askYesNo("you want to remove the columns") if (is.na(Answer) && Answer) dat <- dat[ ,!names(dat) %in% date_na] else print("Columns are not deleted") dat # return(dat) is what we "think" here, but 'return' is rarely necessary/beneficial }
This may be more OCD, but it starts down the road of some "good practices" in defensive programming.