【问题标题】:Using the same argument names in nested function causes unexpected output在嵌套函数中使用相同的参数名称会导致意外输出
【发布时间】:2021-02-27 06:00:45
【问题描述】:

为什么前三个函数(f2、f3、f4)只返回 y 中 id = 1 的行,而 f5 返回 y 的所有行?

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

y <- tibble(id = c(1, 2))


f1 <- function(y, id) {
  y %>% filter(.data$id == {{id}})
}


f2 <- function(id) {
  f1(y, !!id)
}

f3 <- function(id) {
  f1(y, {{id}})
}

f4 <- function(x) {
  f1(y, x)
}

f5 <- function(id) {
  f1(y, id)
}


f2(1)
#> # A tibble: 1 x 1
#>      id
#>   <dbl>
#> 1     1
f3(1)
#> # A tibble: 1 x 1
#>      id
#>   <dbl>
#> 1     1
f4(1)
#> # A tibble: 1 x 1
#>      id
#>   <dbl>
#> 1     1
f5(1)
#> # A tibble: 2 x 1
#>      id
#>   <dbl>
#> 1     1
#> 2     2

reprex package (v0.3.0) 于 2020 年 11 月 15 日创建

【问题讨论】:

    标签: r dplyr functional-programming nested


    【解决方案1】:

    如果你改变你的函数来显示它正在评估什么,它可能更有意义

    f1 <- function(y, id) {
      print(rlang::quo_squash(quo(y %>% filter(.data$id == {{id}}))))
      y %>% filter(.data$id == {{id}})
    }
    

    使用f5,您会得到

    y %>% filter(.data$id == id)
    

    所以它返回id 列等于id 列(即每一行)的所有行。

    在从 data.frame 中选择列时,您应该使用 {{}}。尝试指定文字 data.value 是没有用的。

    如果您将f1 定义为,您的所有示例都将有效

    f1 <- function(y, id) {
      y %>% filter(.data$id == .env$id)
    }
    

    【讨论】:

    • 谢谢!在使用 dplyr 小插图进行编程的任何地方,我都没有看到提到的 .env 代词。你能评论这篇关于.env vs bang-bang的使用吗? https://github.com/tidyverse/dplyr/issues/3286#issuecomment-355501411
    • 该线程来自 2018 年,并且报告的错误似乎不是当前 dplyr 版本中的错误。如果你有一个符号,那么你可以用!! 注入它,但它会首先在 data.frame 中查找一个值。当您没有符号但有文字名称或字符串并希望确保它不会与任何列名冲突时,您通常使用.env
    • 完美的解释。再次感谢!
    猜你喜欢
    • 2017-03-22
    • 2022-09-23
    • 1970-01-01
    • 2017-10-05
    • 2021-08-04
    • 1970-01-01
    • 2016-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多