是否可以使R函数满足以下条件:
-
返回一个列表,只打印第一个元素。(我知道怎么做(
-
将步骤1的结果分配给具有第一个元素类的新对象,然后我可以直接使用管道函数和其他
dplyr
函数。 -
新对象仍然包含原始列表元素。
例如,
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