英文:
R arrange within function on multiple variables not using tripple dot
问题
我想创建一个R函数,除了许多其他功能之外,还可以将数据框按照一组变量进行排列。同时还能够使用desc辅助函数。我看到许多示例只使用单个变量或三个点参数。但我找不到一个符合所有这些条件的可用示例。
我尝试了以下方法(以及使用enexprs/{{}}/eval_tidy的许多变体),但我无法让它起作用:
```R
library(tidyverse)
library(rlang)
dummy_df <- tibble(a = c(1, 1, 2), b = c("bac", "abc", "cba"))
arrange_df <- function(data, sort_vars) {
sort_expr <- enquos(sort_vars)
data <- data %>%
arrange(!!!sort_expr)
return(data)
}
arrange_df(dummy_df, sort_vars = c(desc(a), b))
# 应该和下面的代码效果相同:
dummy_df %>%
arrange(desc(a), b)
<details>
<summary>英文:</summary>
I would like to create an R function that besides many other things, arranges a dataframe on a vector of variables. Also being able to use the desc helper function. I have seen many examples using only a single variable, or the tripple dot argument. But I can't find a working example meeting all these conditions.
I tried the following (and many variations using enexprs/{{}}/eval_tidy), but I can't get it to work:
library(tidyverse)
library(rlang)
dummy_df <- tibble(a = c(1, 1, 2), b = c("bac", "abc", "cba"))
arrange_df <- function(data, sort_vars) {
sort_expr <- enquos(sort_vars)
data <- data %>%
arrange(!!!sort_expr)
return(data)
}
arrange_df(dummy_df, sort_vars = c(desc(a), b))
should be the same as:
dummy_df |>
arrange(desc(a), b)
</details>
# 答案1
**得分**: 1
我不能推荐在不使用省略号的情况下这样做。但如果你真的不想使用它,下面是一种方法(请参见代码中的注释)。
缺点是,如果表达式被包裹在除了 `c()` 或 `list()` 之外的任何其他东西中,这将不起作用(例如 `rlang::list2()`)。为了解决这个问题,你可以强制用户将甚至简单的表达式,比如只是 `a`,包装成 `list(a)` 或 `c(a)`,但这并不是真正用户友好的做法。
我假设你想要使用省略号来实现其他功能。也许先尝试只用一个输入参数来实现那个功能会更容易。
``` r
library(tidyverse)
library(rlang)
dummy_df <- tibble(a = c(1, 1, 2), b = c("bac", "abc", "cba"))
arrange_df <- function(data, sort_vars) {
# 捕获不带环境的表达式
sort_expr <- enexpr(sort_vars)
# 如果未包装在 list() 或 c() 中,则将其包装在 c() 中
if (! deparse(sort_expr[[1]]) %in% c("list", "c")) {
# 我们实际上评估 `sort_expr`,然后再次捕获它并包装在 `c()` 中
sort_expr <- expr(c(!! sort_expr))
}
# 将每个元素转换为表达式并删除第一个表达式,即 c() 或 list()
expr_ls <- as.list(sort_expr)[-1]
# 排列数据
arrange(data, !!! expr_ls)
}
arrange_df(dummy_df, desc(a))
#> # A tibble: 3 × 2
#> a b
#> <dbl> <chr>
#> 1 2 cba
#> 2 1 bac
#> 3 1 abc
arrange_df(dummy_df, c(desc(a), b))
#> # A tibble: 3 × 2
#> a b
#> <dbl> <chr>
#> 1 2 cba
#> 2 1 abc
#> 3 1 bac
arrange_df(dummy_df, c(a, b))
#> # A tibble: 3 × 2
#> a b
#> <dbl> <chr>
#> 1 1 abc
#> 2 1 bac
#> 3 2 cba
在2023-06-22使用 reprex v2.0.2 创建
英文:
I cannot recommend doing this without using the ellipsis. But if you really don't want to use it, then below is one approach (see comments in code).
The downside is, if the expressions are wrapped in anything else apart from c()
or list()
this won't work (for example rlang::list2()
). To overcome this you could force the users to wrap even simple expressions, like just a
, into list(a)
or c(a)
, but that is not really user-friendly.
I assume that you want to use the ellipsis for some other functionality. Maybe it is easier to first try to implement that functionality with just one input argument.
library(tidyverse)
library(rlang)
dummy_df <- tibble(a = c(1, 1, 2), b = c("bac", "abc", "cba"))
arrange_df <- function(data, sort_vars) {
# capture the expression without its environment
sort_expr <- enexpr(sort_vars)
# wrap in c() if not wrapped in list() or c()
if (! deparse(sort_expr[[1]]) %in% c("list", "c")) {
# we literally evaluate `sort_expr` and capture it again wrapped in `c()`
sort_expr <- expr(c(!! sort_expr))
}
# turn every element into an expression and delete the first expression, c() or list()
expr_ls <- as.list(sort_expr)[-1]
# arrange the data
arrange(data, !!! expr_ls)
}
arrange_df(dummy_df, desc(a))
#> # A tibble: 3 × 2
#> a b
#> <dbl> <chr>
#> 1 2 cba
#> 2 1 bac
#> 3 1 abc
arrange_df(dummy_df, c(desc(a), b))
#> # A tibble: 3 × 2
#> a b
#> <dbl> <chr>
#> 1 2 cba
#> 2 1 abc
#> 3 1 bac
arrange_df(dummy_df, c(a, b))
#> # A tibble: 3 × 2
#> a b
#> <dbl> <chr>
#> 1 1 abc
#> 2 1 bac
#> 3 2 cba
<sup>Created on 2023-06-22 with reprex v2.0.2</sup>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论