【问题标题】:R use bang-bang within a glue statementR 在胶水语句中使用 bang-bang
【发布时间】:2021-03-01 09:44:16
【问题描述】:

我想创建一个简单的函数,它接受一个数据框和用户为该数据框中的两列提供的名称。目的是允许它轻松地与dplyr 管道一起工作。它将产生一个粘合字符串的字符向量:

func <- function(data, last, first) {
  last <- rlang::enquo(last)
  first <- rlang::enquo(first)
  
  glue::glue_data(data, "{!!last}, {!!first}")
}

我希望用户能够打电话:

df %>% func(lastName, firstName)

这将产生一个包含多个值的字符向量,格式为Smith, John

我的函数目前不起作用,因为 bang-bang 运算符在 glue_data 的上下文中不起作用。如何在仍然使用 NSE 的同时解决这个问题?我收到的错误是:

Error: Quosures can only be unquoted within a quasiquotation context.

代表:

df <- data.frame(lastName = c("Smith", "Bond", "Trump"), firstName = c("John","James","Donald"))

> df
  lastName firstName
1    Smith      John
2     Bond     James
3    Trump    Donald

预期输出

> glue::glue_data(df, "{lastName}, {firstName}")

Smith, John
Bond, James
Trump, Donald

但是,我希望能够通过使用我的函数并调用来实现预期的输出:

df %>% func(lastName, firstName)

以上是我实际用例的简化版本,我实际上将在后续函数中调用glue 语句作为参数:

biggerfn <- function(data, subject, first, last) {
  subject <- rlang::enquo(subject)
  first <- rlang::enquo(first)
  last <- rlang::enquo(last)
  
  data %>%
    dplyr::distinct(!!subject, !!first, !!last) %>%
    smallerfunc(!!subject, glue::glue_data(data, "{!!last}, {!!first}"))
}

【问题讨论】:

    标签: r rlang nse r-glue


    【解决方案1】:

    我不知道你是否致力于glue,但这可以使用tidyr::unite 轻松完成:

    func <- function(data, last, first) {
        data %>%
            tidyr::unite(result, {{last}}, {{first}}, sep=", ")
    }
    
    df %>% func(lastName, firstName)
    #           result
    #  1   Smith, John
    #  2   Bond, James
    #  3 Trump, Donald
    
    # Optionally, follow up with: 
    #   %>% dplyr::pull(result)
    # to retrieve the column
    

    这里,{{x}}!!enquo(x) 的简写。

    【讨论】:

    • 这是我所希望的,谢谢!我不承诺glue
    【解决方案2】:

    我认为您不想强制评估 firstlast。您只希望名称构造字符串"{lastName}, {firstName}"

    library(dplyr)
    library(rlang)
    library(glue)
    
    func <- function(data, last, first) {
      first <- as_name(enquo(first))
      last <- as_name(enquo(last))
      
      glue_data(
        data,
        glue("{[last]}, {[first]}", .open = "[", .close = "]")
      )
    }
    
    df %>% func(lastName, firstName)
    #> Smith, John
    #> Bond, James
    #> Trump, Donald
    

    对于您的新示例,请在内部 glue 调用中调用 as_name

    df <- data.frame(
      lastName = c("Smith", "Bond", "Trump"),
      firstName = c("John","James","Donald"),
      other = 1:3
    )
    
    biggerfn <- function(data, subject, first, last) {
      subject <- enquo(subject)
      first <- enquo(first)
      last <- enquo(last)
      
      data %>%
        distinct(!!subject, !!first, !!last) %>%
        transmute(
          !!subject := glue_data(
            data,
            glue("{[as_name(last)]}, {[as_name(first)]}", .open = "[", .close = "]")
          )
        )
    }
    
    biggerfn(df, other, firstName, lastName)
    #>           other
    #> 1   Smith, John
    #> 2   Bond, James
    #> 3 Trump, Donald
    

    【讨论】:

    • 我的想法是我会复制调用 glue::glue_data(df, "{lastName}, {firstName}" 但使用 NSE。有趣的是它不会那样工作。请查看我的编辑,了解为什么我不确定是否可以实施您的解决方案。
    • 您会看到我不能提前调用as_name,因为我仍然需要在管道中强制评估lastfirst
    • as_name 可以在glue 内部调用。请参阅我的更新答案。
    • 为什么glue必须在glue_data内调用?我无法理解它在做什么。
    • 内部glue 正在构造表达式字符串。分两步考虑:glue_string &lt;- "{lastName}, {firstName}"glue_data(data, glue_string)。第一步可以改写为glue_string &lt;- glue("{[as_name(last)]}, {[as_name(first)]}", .open = "[", .close = "]")
    猜你喜欢
    • 1970-01-01
    • 2022-01-06
    • 2021-12-04
    • 2013-02-14
    • 1970-01-01
    • 2021-03-09
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    相关资源
    最近更新 更多