You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R函数中使用dplyr::arrange()失效问题及修复咨询

问题:my_function无法按指定arrange_by参数排序

编写的my_function()无法按照指定的arrange_by=参数进行排序,例如调用my_function(DATA, study, time, treat_grp, arrange_by = "treat_grp")或my_function(DATA, study, time, treat_grp, arrange_by = "time")时,并未发生排序操作,请问如何修复?

library(tidyverse)

my_function <- function(data, cluster, ..., arrange_by = NULL) {
  cluster <- rlang::ensym(cluster)
  cat_mod <- rlang::ensyms(...)
  cat_nms <- purrr::map_chr(cat_mod, rlang::as_string)  
  
  data %>% 
    count(!!cluster, !!!rlang::syms(cat_nms)) %>% 
    group_by(!!!rlang::syms(cat_nms)) %>% 
    summarize(`n study` = n(),
              `n effect` = sum(n)) %>% 
    ungroup() %>%  
    tidyr::complete(!!!rlang::syms(cat_nms), fill = list(`n study` = 0, `n effect` = 0)) %>% 
    arrange(if(is.null(arrange_by)) all_of(cat_nms[1]) else all_of(arrange_by))
}

#--------------------------------------------------
DATA <- structure(
  list(
    study = c(1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5),
    time = c(
      "baseline", "posttest1", "posttest2", "baseline", "posttest1",
      "posttest2", "posttest1", "posttest1", "posttest1", "posttest1",
      "posttest1", "posttest1", "posttest1", "posttest1", "posttest2"
    ),
    treat_grp = c(
      "conventional", "conventional", "conventional", "conventional",
      "conventional", "conventional", "conventional", "framework_notes",
      "conventional", "conventional", "conventional", "conventional",
      "conventional", "vocabulary_notebook", "vocabulary_notebook"
    )
  ), 
  row.names = c(NA, -15L), 
  class = "data.frame"
)

# 这些调用没有产生排序效果
my_function(DATA, study, time, treat_grp, arrange_by = "treat_grp")
my_function(DATA, study, time, treat_grp, arrange_by = "time")

问题原因

核心问题出在arrange()中的if语句用法:arrange(if(is.null(arrange_by)) all_of(cat_nms[1]) else all_of(arrange_by))。

if语句在这里返回的是字符串(如"treat_grp"),而arrange()需要的是列对象而非字符串。尽管all_of()可以将字符串转换为列引用,但嵌套在if语句中时,arrange()无法正确解析这个逻辑,导致排序操作失效。


修复方案

提供两种简洁可行的修复方式:

方式一:用rlang::sym()转换为符号后解引用

直接将字符串转为列符号,通过!!解引用后传入arrange():

my_function <- function(data, cluster, ..., arrange_by = NULL) {
  cluster <- rlang::ensym(cluster)
  cat_mod <- rlang::ensyms(...)
  cat_nms <- purrr::map_chr(cat_mod, rlang::as_string)  
  
  data %>% 
    count(!!cluster, !!!rlang::syms(cat_nms)) %>% 
    group_by(!!!rlang::syms(cat_nms)) %>% 
    summarize(`n study` = n(),
              `n effect` = sum(n)) %>% 
    ungroup() %>%  
    tidyr::complete(!!!rlang::syms(cat_nms), fill = list(`n study` = 0, `n effect` = 0)) %>% 
    arrange(!!if(is.null(arrange_by)) rlang::sym(cat_nms[1]) else rlang::sym(arrange_by))
}

方式二:提前确定排序列再传入

先通过条件判断得到目标排序列的字符串,再用all_of()传入arrange():

my_function <- function(data, cluster, ..., arrange_by = NULL) {
  cluster <- rlang::ensym(cluster)
  cat_mod <- rlang::ensyms(...)
  cat_nms <- purrr::map_chr(cat_mod, rlang::as_string)
  
  # 提前确定排序列
  sort_col <- if(is.null(arrange_by)) cat_nms[1] else arrange_by
  
  data %>% 
    count(!!cluster, !!!rlang::syms(cat_nms)) %>% 
    group_by(!!!rlang::syms(cat_nms)) %>% 
    summarize(`n study` = n(),
              `n effect` = sum(n)) %>% 
    ungroup() %>%  
    tidyr::complete(!!!rlang::syms(cat_nms), fill = list(`n study` = 0, `n effect` = 0)) %>% 
    arrange(all_of(sort_col))
}

修复后重新调用函数,即可看到按指定列排序的结果:

# 按treat_grp排序
my_function(DATA, study, time, treat_grp, arrange_by = "treat_grp")

# 按time排序
my_function(DATA, study, time, treat_grp, arrange_by = "time")

内容的提问来源于stack exchange,提问作者Simon Harmel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:04:51