Description
I recently re-implemented an existing S3 class using vctrs and have noticed that sapply()
/ lapply()
don't necessarily transfer the names of the input to the output. (I was not actually relying on this in any meaningful way, mind you, but I noticed that a piece of documentation started to render differently.)
library(vctrs)
x <- new_vctr(1:3, class = "foofy")
names(x) <- letters[1:3]
x
#> <foofy[3]>
#> a b c
#> 1 2 3
z <- 1:3
names(z) <- letters[1:3]
z
#> a b c
#> 1 2 3
f <- function(x) "blah"
sapply(x, f)
#> [1] "blah" "blah" "blah"
sapply(z, f)
#> a b c
#> "blah" "blah" "blah"
Why do the names of x
not transfer, while those for z
do? What's weird is that it seems to vary by the function being applied. Here both have names. (Well, it's slightly less surprising now that I see the inner/outer name thing I show below.)
g <- function(x) x
sapply(x, g)
#> a b c
#> 1 2 3
sapply(z, g)
#> a b c
#> 1 2 3
Looking at the source of sapply()
, these seem to be important differences. The vctrs-made vector returns FALSE
for is.vector()
, which means it gets sent through as.list()
and as.list()
also does something quite different for x
vs. z
, in terms of inner vs outer names.
is.vector(x)
#> [1] FALSE
is.vector(z)
#> [1] TRUE
as.list(x)
#> [[1]]
#> <foofy[1]>
#> a
#> 1
#>
#> [[2]]
#> <foofy[1]>
#> b
#> 2
#>
#> [[3]]
#> <foofy[1]>
#> c
#> 3
as.list(z)
#> $a
#> [1] 1
#>
#> $b
#> [1] 2
#>
#> $c
#> [1] 3
Created on 2021-07-19 by the reprex package (v2.0.0.9000)