R函数打印并分配返回列表的第一个元素,然后可以使用管道



是否可以使R函数满足以下条件:

  1. 返回一个列表,只打印第一个元素。(我知道怎么做(

  2. 将步骤1的结果分配给具有第一个元素类的新对象,然后我可以直接使用管道函数和其他dplyr函数。

  3. 新对象仍然包含原始列表元素。

例如,

my_tbl <- function(x) {
dat <- tibble(num = x)
words <- paste("input is", x)
res <- list(dat = dat, words = words)
class(res) <- c("myclass", "list")
return(res)
}
print.myclass <- function(x) {
print(x[[1]])
invisible(x)
}
a <- my_tbl(1:2) 
a
# A tibble: 2 × 1
num
<int>
1     1
2     2
> a$words
[1] "input is 1" "input is 2"
a$dat %>%
mutate(b = 3)
# A tibble: 2 × 2
num     b
<int> <dbl>
1     1     3
2     2     3

是否可以直接使用dplyr函数,例如mutate,而不添加任何中间步骤,例如a$dat,以获得相同的结果?像这样:

a %>%
mutate(b = 3)
# A tibble: 2 × 2
num     b
<int> <dbl>
1     1     3
2     2     3

我不确定这是否是一个有效的解决方案,但一个简单的方法是定义一个自定义的mutate方法:

mutate.myclass <- function(x, ...) {
x$dat <- mutate(x$dat, ...)
x
}

这允许你做:

a <- my_tbl(1:2) 
a %>%
mutate(b = 3)
#> # A tibble: 2 x 2
#>     num     b
#>   <int> <dbl>
#> 1     1     3
#> 2     2     3

同时仍然保留整个对象a:

str(a)
#> List of 2
#>  $ dat  : tibble [2 × 1] (S3: tbl_df/tbl/data.frame)
#>   ..$ num: int [1:2] 1 2
#>  $ words: chr [1:2] "input is 1" "input is 2"
#>  - attr(*, "class")= chr [1:2] "myclass" "list"

另一个解决方案是更改输出对象的结构。只需创建一个tibble并将words添加为attribute即可。当使用{dplyr}进行操作时,这应该会起作用。然而,有一些函数会丢弃attributes,这使得这是一种有点不可靠的方法(取决于您使用这个新对象的函数类型(。

library(dplyr)
my_tbl <- function(x) {
dat <- tibble(num = x)
words <- paste("input is", x)
attr(dat, "words") <- words
return(dat)
}
a <- my_tbl(1:2) 
a %>%
mutate(b = 3)
#> # A tibble: 2 x 2
#>     num     b
#>   <int> <dbl>
#> 1     1     3
#> 2     2     3
str(a)
#> tibble [2 × 1] (S3: tbl_df/tbl/data.frame)
#>  $ num: int [1:2] 1 2
#>  - attr(*, "words")= chr [1:2] "input is 1" "input is 2"

由reprex包于2021-12-04创建(v0.3.0(

使用purrr::list_merge。第二个参数必须与要合并的列表成员具有相同的名称。

library(dplyr)
library(purrr)
a %>%
list_merge(dat = list(b = 3)) %>%
print()
## A tibble: 2 x 2
#    num     b
#  <int> <dbl>
#1     1     3
#2     2     3

编辑

"myclass"类对象的mutate方法,如TimTeaFan的答案中所示,将有一个额外的参数,即要变异的列表成员。这将保留列表结构。

mutate.myclass <- function(x, y, ...) {
nm <- deparse(substitute(y))
tmp <- x[[nm]] %>% mutate(...)
x[[nm]] <- tmp
x
}
a %>%
mutate(dat, b = 3)
## A tibble: 2 x 2
#    num     b
#  <int> <dbl>
#1     1     3
#2     2     3
a %>%
mutate(dat, b = 3) %>%
str()
#List of 2
# $ dat  : tibble [2 × 2] (S3: tbl_df/tbl/data.frame)
#  ..$ num: int [1:2] 1 2
#  ..$ b  : num [1:2] 3 3
# $ words: chr [1:2] "input is 1" "input is 2"
# - attr(*, "class")= chr [1:2] "myclass" "list"

如果没有管道,额外的论点就更明显了:

mutate(a, dat, b = 3)
## A tibble: 2 x 2
#    num     b
#  <int> <dbl>
#1     1     3
#2     2     3

相关内容

最新更新