[R] sapply(NULL, ...) returns a list?!?

Prof Brian Ripley ripley at stats.ox.ac.uk
Fri Jul 22 10:29:54 CEST 2005


On Fri, 22 Jul 2005, Henrik Bengtsson wrote:

> Hi,
>
> I bet this one has be asked before, but doing
>
>  sapply(x, FUN=as.character)
>
> where 'x' is a vector, then the result "should [] be simplified to a
> vector" according to ?sapply, correct?  However,
>
>  > x <- 1:10
>  > sapply(x, FUN=as.character)
>  [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10"
>  > sapply(x[1], FUN=as.character)
>  [1] "1"
>
> But,
>
>  > sapply(x[c()], FUN=as.character)
>  list()
>
> or equivalent,
>
>  > sapply(NULL, FUN=as.character)
>  list()

A list is a vector of length 0, BTW.

> Please enlight me if I missed the reason for this.

Well, FUN is not required to work on a 0-length input, and if you have 
nothing to call it on you have no result to know what the result type 
should be.

If FUN is vectorized (as as.character is) you would not be using sapply 
but calling FUN directly.  So it is quite reasonable to assume that FUN 
needs a length-one input.

A secondary consideration is that this is the behaviour of S, and quite a 
lot of code relies on it.

> Looking at the code for sapply(),
>
>> sapply
> function (X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
> {
>     FUN <- match.fun(FUN)
>     answer <- lapply(as.list(X), FUN, ...)
>     if (USE.NAMES && is.character(X) && is.null(names(answer)))
>         names(answer) <- X
>     if (simplify && length(answer) && length(common.len <-
>                  unique(unlist(lapply(answer, length)))) == 1) {
>         if (common.len == 1)
>             unlist(answer, recursive = FALSE)
>         else if (common.len > 1)
>             array(unlist(answer, recursive = FALSE),
>                   dim = c(common.len, length(X)),
>                   dimnames = if (!(is.null(n1 <- names(answer[[1]]))
>                                  & is.null(n2 <- names(answer))))
>                              list(n1, n2))
>         else answer
>     }
>     else answer
> }
>
> I see that the above behavior is coded for (because of the "&&
> length(answer) &&" statement), but is this wanted?  I would like to get
> a vector of length zero, in line with
>
>   if (simplify && length(X) == 0)
>     answer <- FUN(X, ...)
>   else
>     answer <- lapply(as.list(X), FUN, ...)

That's not a valid call in general.

-- 
Brian D. Ripley,                  ripley at stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595




More information about the R-help mailing list