-
Notifications
You must be signed in to change notification settings - Fork 71
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 3Looking 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] 3Created on 2021-07-19 by the reprex package (v2.0.0.9000)