Hong Ooi
Hong Ooi

Reputation: 57686

Making a string concatenation operator in R

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

Answers (5)

Lytze
Lytze

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

statsmaths
statsmaths

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

VitoshKa
VitoshKa

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

jverzani
jverzani

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

Dirk is no longer here
Dirk is no longer here

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

Related Questions