[R] Recursive function calls

Hadley Wickham hadley at rice.edu
Fri Aug 3 22:52:00 CEST 2012


On Fri, Aug 3, 2012 at 12:19 PM, Rui Barradas <ruipbarradas at sapo.pt> wrote:
> Hello,
>
> This seems to work.
>
> trim2 <- function(x) {
>     if(is.atomic(x))
>
>         gsub("^[[:space:]]+|[[:space:]]+$", "", x)
>     else
>         sapply(x, function(y) trim2(y))
> }
>

Using sapply is a bit dangerous here. Compare:

trim2(list(c("a", "b"), c("c", "d")))
#      [,1] [,2]
# [1,] "a"  "c"
# [2,] "b"  "d"

trim2(list(c("a", "b"), c("c", "d", "e")))
# [[1]]
# [1] "a" "b"
#
# [[2]]
# [1] "c" "d" "e"

which I think is rather undesirable behaviour. sapply is suitable for
interactive use, but you should never use it inside a function because
you don't know what sort of data structure you'll get back.

I think it's also a bit unsafe to accept any type of input - you're
generally better off being explicit.  This leads to trim3:

trim3 <- function(x) {
  if (is.character(x)) {
    gsub("^[[:space:]]+|[[:space:]]+$", "", x)
  } else if (is.list(x)) {
    lapply(x, trim3)
  } else {
    warning("Invalid input: ", paste(class(x), sep = "/"))
    x
  }
}

trim2(list(c("a", "b"), c("c", "d")))
trim3(list(c("a", "b"), c("c", "d")))

But then the function isn't extensible for new types of input, which
suggests an S3 implementation:

trim4 <- function(x) UseMethod("trim4")
trim4.character <- function(x) gsub("^[[:space:]]+|[[:space:]]+$", "", x)
trim4.list <- function(x) lapply(x, trim4)
trim4.default <- function(x) {
  warning("Invalid input")
  x
}

Hadley

-- 
Assistant Professor / Dobelman Family Junior Chair
Department of Statistics / Rice University
http://had.co.nz/



More information about the R-help mailing list