Создание оператора конкатенации строк в R - PullRequest
43 голосов
/ 19 января 2011

Мне было интересно, как можно написать оператор конкатенации строк в R, что-то вроде || в SAS + в Java / C # или & в Visual Basic.

Самый простой способ - создать специальный оператор с использованием%, например

`%+%` <- function(a, b) paste(a, b, sep="")

но это приводит к большому количеству уродливых % в коде.

Я заметил, что + определено в группе Ops, и вы можете написать S4-методы для этой группы, так что, возможно, что-то подобное будет для вас. Тем не менее, у меня нет опыта работы с языком S4. Как бы я изменил вышеуказанную функцию, чтобы использовать S4?

Ответы [ 5 ]

40 голосов
/ 11 августа 2013

Как уже упоминали другие, вы не можете переопределить запечатанный метод S4 "+".Однако вам не нужно определять новый класс для определения функции сложения для строк;это не идеально, так как заставляет вас преобразовывать класс строк и, следовательно, приводит к более уродливому коду.Вместо этого можно просто перезаписать функцию «+»:

"+" = function(x,y) {
    if(is.character(x) || is.character(y)) {
        return(paste(x , y, sep=""))
    } else {
        .Primitive("+")(x,y)
    }
}

Тогда все следующее должно работать как положено:

1 + 4
1:10 + 4 
"Help" + "Me"

Это решение выглядит как хак, посколькубольше не используют формальные методы, но это единственный способ получить точное поведение, которое вы хотели.

22 голосов
/ 04 июня 2015

Я попробую это (относительно более чистый раствор S3)

`+` <- 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')

Приведенный выше код изменит + на общий, и установите +.default на исходный +, затем добавьте новый метод +.character на +

22 голосов
/ 19 января 2011

Вы также можете использовать классы S3 для этого:

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
11 голосов
/ 19 января 2011

Если бы R полностью соответствовал S4, следующего было бы достаточно:

setMethod("+",
          signature(e1 = "character", e2 = "character"),
          function (e1, e2) {
              paste(e1, e2, sep = "")
      })

Но это дает ошибку, что метод запечатан: ((. Надеюсь, это изменится в версиях функции R.

Лучшее, что вы можете сделать, это определить новый класс "string", который будет вести себя точно так же, как класс "персонажа":

setClass("string", contains="character")
string <- function(obj) new("string", as.character(obj))

и определите наиболее общий метод, который позволяет R:

setMethod("+", signature(e1 = "character", e2 = "ANY"),
          function (e1, e2) string(paste(e1, as.character(e2), sep = "")))

Теперь попробуйте:

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"
8 голосов
/ 19 января 2011

Вы дали себе правильный ответ - все в R является функцией, и вы не можете определить новые операторы.Так что %+% настолько хорош, насколько это возможно.

...