I'm trying to use a function that if the answer is a small integer (10 or less), then it will give the English word for the number (one for 1, two for 2, etc.) and the numeral for larger numbers. The problem I'm running into is that while using english::english inside the ifelse, it is still giving me the numeral. Here is a simple repex:
test_small <- 4
english::english(test_small)
ifelse(test_small < 11, english::english(test_small),test_small)
ifelse(test_small < 11, english::english(test_small),"fail")
When outside the ifelse statement, english::english(test_small) produces the desired result of "four". Once I wrap it in the ifelse statement though, I get the result of "4". To check and see if I was for some reason getting the "false result", I also made the second ifelse statement that would simply spit out the word "fail". But nope, I still get "4" and not "four" as expected.
Any ideas what is going on?
CodePudding user response:
I am unsure of the exact problem but a simple solution is to wrap as.charachter() around english(test_small)
test_small <- 4
english::english(test_small)
ifelse(test_small < 11, as.character(english::english(test_small)), test_small)
ifelse(test_small < 11, as.character(english::english(test_small)), "fail")
CodePudding user response:
This is a S3 class objects issue.
First see the definition of the function english by printing its body.
library(english)
english
#function (x, ...)
#{
# UseMethod("english")
#}
#<bytecode: 0x55f20eecccc8>
#<environment: namespace:english>
So the function is a generic, see its methods.
methods(english)
#[1] english.default* english.numeric*
#see '?methods' for accessing help and source code
There are two methods but only the method for class "numeric" does something usefull. Both methods are marked by an asterisk, so they are not exported from the package namespace. From help(methods").
The S3 method name is followed by an asterisk * if the method definition is not exported from the package namespace in which the method is defined.
The way to get its source is with getAnywhere.
getAnywhere("english.numeric")
#A single object matching ‘english.numeric’ was found
#It was found in the following places
# registered S3 method for english from namespace english
# namespace:english
#with value
#
#function (x, UK, ...)
#{
# if (missing(UK)) {
# UK <- getOption("english.UK", !grepl("^(en_us|english_united)",
# tolower(Sys.getlocale("LC_CTYPE"))))
# UK <- isTRUE(UK) || identical(UK, "UK")
# }
# else {
# UK <- as.logical(UK)[1]
# if (is.na(UK))
# stop("Bad specification of the UK flag. Must be logical scalar")
# }
# structure(x, class = "english", useUK = UK)
#}
<bytecode: 0x55f20ef091c8>
<environment: namespace:english>
>
The method checks the locale and returns the object with a new class attribute, class "english".
So this is a print method artifact.
getAnywhere("print.english")
#A single object matching ‘print.english’ was found
#It was found in the following places
# registered S3 method for print from namespace english
# namespace:english
#with value
#
#function (x, ...)
#{
# print(noquote(as.character.english(x)))
# invisible(x)
#}
#<bytecode: 0x55f20ef09750>
#<environment: namespace:english>
And now it's in the method as.character for objects of class "english" that the numbers become words.
ifelse(test_small < 11, as.character(english::english(test_small)), test_small)
#[1] "four" "five" "six"
ifelse(test_small < 11, as.character(english::english(test_small)), "fail")
#[1] "four" "five" "six"
