Reputation: 57686
I was wondering how one might go about writing a string concatenation operator in R, something like || in SAS, + in Java/C# or & in Visual Basic.
The easiest way would be to create a special operator using %, like
`%+%` <- function(a, b) paste(a, b, sep="")
but this leads to lots of ugly %
's in the code.
I noticed that +
is defined in the Ops group, and you can write S4 methods for that group, so perhaps something like that would be the way to go. However, I have no experience with S4 language features at all. How would I modify the above function to use S4?
Upvotes: 48
Views: 15126
Reputation: 765
I'll try this (relatively more clean S3 solution)
`+` <- function (e1, e2) UseMethod("+")
`+.default` <- function (e1, e2) .Primitive("+")(e1, e2)
`+.character` <- function(e1, e2)
if(length(e1) == length(e2)) {
paste(e1, e2, sep = '')
} else stop('String Vectors of Different Lengths')
Code above will change +
to a generic, and set the +.default
to the original +
, then add new method +.character
to +
Upvotes: 29
Reputation: 496
As others have mentioned, you cannot override the sealed S4 method "+". However, you do not need to define a new class in order to define an addition function for strings; this is not ideal since it forces you to convert the class of strings and thus leading to more ugly code. Instead, one can simply overwrite the "+" function:
"+" = function(x,y) {
if(is.character(x) || is.character(y)) {
return(paste(x , y, sep=""))
} else {
.Primitive("+")(x,y)
}
}
Then the following should all work as expected:
1 + 4
1:10 + 4
"Help" + "Me"
This solution feels a bit like a hack, since you are no longer using formal methods but its the only way to get the exact behavior you wanted.
Upvotes: 48
Reputation: 8523
If R would thoroghlly comply with S4, the following would have been enough:
setMethod("+",
signature(e1 = "character", e2 = "character"),
function (e1, e2) {
paste(e1, e2, sep = "")
})
But this gives an error that the method is sealed :((. Hopefully this will change in the feature versions of R.
The best you can do is to define new class "string" which would behave exactly as "character" class:
setClass("string", contains="character")
string <- function(obj) new("string", as.character(obj))
and define the most general method which R allows:
setMethod("+", signature(e1 = "character", e2 = "ANY"),
function (e1, e2) string(paste(e1, as.character(e2), sep = "")))
now try:
tt <- string(44444)
tt
#An object of class "string"
#[1] "44444"
tt + 3434
#[1] "444443434"
"sfds" + tt
#[1] "sfds44444"
tt + tt
#[1] "4444444444"
343 + tt
#Error in 343 + tt : non-numeric argument to binary operator
"sdfs" + tt + "dfsd"
#An object of class "string"
#[1] "sdfs44444dfsd"
Upvotes: 13
Reputation: 5700
You can also use S3 classes for this:
String <- function(x) {
class(x) <- c("String", class(x))
x
}
"+.String" <- function(x,...) {
x <- paste(x, paste(..., sep="", collapse=""), sep="", collapse="")
String(x)
}
print.String <- function(x, ...) cat(x)
x <- "The quick brown "
y <- "fox jumped over "
z <- "the lazy dog"
String(x) + y + z
Upvotes: 25
Reputation: 368181
You have given yourself the correct answer -- everything in R is a function, and you cannot define new operators. So %+%
is as good as it gets.
Upvotes: 9