感觉这个dplyr包里面的这个bang-bang概念有点不好理解,比如我有两段代码

# code 1
library(dplyr)

df <- data.frame(x = 1:3, y = 4:6)

var_name <- "x"

df %>% 
  filter(!!var_name > 1)

和这段代码

# code 2
library(dplyr)

df <- data.frame(x = 1:3, y = 4:6)

var_name <- "x"

df %>% 
  filter(get(var_name) > 1)

得到的结果是一样的,那么具体的get函数和!!有什么区别呢?

    贡献第三种写法,tidyverse 帮助里提到如何传递参数进tidyverse函数

    library(dplyr)
    
    df <- data.frame(x = 1:3, y = 4:6)
    
    var_name <- "x"
    
    
    df1=
    df %>% 
      filter(get(var_name) > 1)
    
    df2= 
    df %>% 
      filter(.data[[var_name]] > 1)
    
    
    identical(df1,df2)
    #> [1] TRUE

    <sup>Created on 2023-05-19 with reprex v2.0.2</sup>

      tctcab 这个例子我是能理解的 ,我倒不是不能用代码实现,主要感觉这几种写法的区别在哪

      LTkongjianyang

      !!会用在自定义函数中处理传入参数的时候,会配合enquosymdata_sim啥的函数,而且一般不会显式使用了。你再检查一下你的例子代码的结果,两者运行出来是不一样的:

      1. filter(!!var_name > 1实际会变成filter("x" > 1)(好吧这里我也不是很确定),是一个字符串在和1比大小,得到的是一个一维的TRUE,然后这个判断结果经过循环,于是把整个df的所有行都取出来了。所以其实应该

        var_name <- sym("x")
        df %>% 
            filter(!!var_name > 1)
      2. filter(get(var_name) > 1会取到数据框中的x列,经过判断后只有2、3行才会被取出来。

      get是来自于base R的函数,并不是tidyverse系列的。它的第二个参数pos可以指定到底从哪里开始搜索对应变量的值。所以如果你当前的环境里已经有一个x,而你想以这个x来进行判断的话,那么可以

      df <- data.frame(x = 1:3, y = 4:6)
      x <- -(1 : 3)
      var_name <- "x"
      # get的默认位置是-1
      df %>%
          filter(get(var_name, pos = -1) > 1)
      # 从 pos = 1 开始进行get,这样会搜索到当前环境中的`x = c(-1, -2, -3)`
      df %>%
          filter(get(var_name, pos = 1) > 1)

      像这个例子里,第一个做法会得到2行,第二个做法则得到0行。而如果想采用tidyeval系列的做法,则是像 tctcab 提及的.data.env

      df %>%
          filter(.data[[var_name]] > 1)
      
      df %>%
          filter(.env[[var_name]] > 1)

      关于这个消除歧义的话题,可以参考The data mask ambiguity