英文:
What is the difference between !! and !!as.symbol?
问题
将!!
应用于字符串而不是符号会导致R语言将字符串解释为变量名,然后尝试过滤数据框中不满足条件的行。在你的示例中,colname
是一个字符串,它包含变量名"a"。所以,当你执行以下操作时:
df |> filter(!!colname<3)
R语言将尝试筛选数据框df
中"a"列中小于3的行。但是,在数据框中不存在名为"a"的列,因此条件不成立,导致返回一个空数据框。这并不会引发错误,因为R语言允许在筛选中使用不存在的列名,只是结果将是空的。
另一方面,如果你应用!!
到一个符号,R语言将把符号解释为实际的变量,然后执行筛选操作。在你的示例中,!!as.symbol(colname)
将"a"解释为实际的变量名,并且筛选操作将根据该变量的值来过滤数据框,因此它返回了满足条件的行。
英文:
Consider this example:
library(dplyr)
df <- data.frame(a=1:5,b=6:10)
> df
a b
1 1 6
2 2 7
3 3 8
4 4 9
5 5 10
colname <- "a"
df |> filter(!!as.symbol(colname)<3)
a b
1 1 6
2 2 7
df |> filter(!!colname<3)
[1] a b
<0 rows> (or 0-length row.names)
What does applying !!
to a string rather than a symbol achieves, and why does it return an empty dataframe instead of an error?
答案1
得分: 6
让我们首先扩展一下问题中的 df
示例,然后是 df2
,它是 df
加上一个名为 colname
的额外列。
无论 colname
是否是一列:
-
!!as.symbol(colname)
将a
列的值返回为一个向量 -
!!colname
返回字符字符串"a"
-
!!"colname" 返回字符字符串
"colname"
然而,!!as.symbol("colname")
的行为取决于 colname
是否是列名。
df <- data.frame(a=1:5,b=6:10);
colname <- "a"
look <- function(x) { str(x); x }
df |> filter(look(!!as.symbol(colname)) < 3) |> invisible()
## int [1:5] 1 2 3 4 5
df |> filter(look(!!as.symbol("colname")) < 3) |> invisible()
## chr "a"
df |> filter(look(!!colname) == "a") |> invisible()
## chr "a"
df |> filter(look(!!"colname") == "a") |> invisible()
## chr "colname"
####
df2 <- data.frame(a=1:5,b=6:10,colname=c(11:14, 1));
colname <- "a"
look <- function(x) { str(x); x }
df2 |> filter(look(!!as.symbol(colname)) < 3) |> invisible()
## int [1:5] 1 2 3 4 5
df2 |> filter(look(!!as.symbol("colname")) < 3) |> invisible()
## num [1:5] 11 12 13 14 1
df2 |> filter(look(!!colname) == "a") |> invisible()
## chr "a"
df2 |> filter(look(!!"colname") == "a") |> invisible()
## chr "colname"
英文:
Let us expand the example first with the df
in the question and then df2
which is df
plus an extra column called colname
.
Whether or not colname
is a column:
-
!!as.symbol(colname)
returns the value of thea
column as a vector -
!!colname
returns the character string"a"
-
!!"colname" returns the character string
"colname"
However, !!as.symbol("colname")
acts differently depending on whether colname
is a column name or not.
df <- data.frame(a=1:5,b=6:10);
colname <- "a"
look <- function(x) { str(x); x }
df |> filter(look(!!as.symbol(colname)) < 3) |> invisible()
## int [1:5] 1 2 3 4 5
df |> filter(look(!!as.symbol("colname")) < 3) |> invisible()
## chr "a"
df |> filter(look(!!colname) == "a") |> invisible()
## chr "a"
df |> filter(look(!!"colname") == "a") |> invisible()
## chr "colname"
####
df2 <- data.frame(a=1:5,b=6:10,colname=c(11:14, 1));
colname <- "a"
look <- function(x) { str(x); x }
df2 |> filter(look(!!as.symbol(colname)) < 3) |> invisible()
## int [1:5] 1 2 3 4 5
df2 |> filter(look(!!as.symbol("colname")) < 3) |> invisible()
## num [1:5] 11 12 13 14 1
df2 |> filter(look(!!colname) == "a") |> invisible()
## chr "a"
df2 |> filter(look(!!"colname") == "a") |> invisible()
## chr "colname"
答案2
得分: 2
如果您查看 !!
的帮助页面 (help("!!")
),这将重定向您到 rlang
包中的 inject
函数。通过组合 inject
和 substitute
函数,您可以逻辑地重建要评估的表达式。
使用 !!colname < 3)
,其中 colname = "a"
,您正在检查字符串 "a"
是否小于 3,而使用 !!as.symbol(colname) < 3)
,您正在检查名为 a
的变量是否小于 3。
考虑您的示例,在替代 colname
后,以下表达式展示了两种情况之间的差异:
colname <- "a"
### 使用 !!colname < 3) ###
rlang::inject(substitute(
df |>
filter(!!colname < 3)
))
# filter(df, "a" < 3) # 包含字符串 "a"
### 使用 !!as.symbol(colname) < 3) ###
rlang::inject(substitute(
df |>
filter(!!as.symbol(colname) < 3)
))
# filter(df, a < 3) # 包含变量 a
英文:
If you look at the help page of !!
(help("!!")
), this would redirect you to the function inject
in the package rlang
. And by combining inject
and subsititute
functions, you can logically rebuild the expression that is evaluated.
Using !!colname < 3)
, where colname = "a"
, your are checking if the string "a"
is lower than 3 while with !!as.symbol(colname) < 3)
you are checking if the variable named a
is lower than 3.
Considering your example, the following expressions show the difference between the two cases after colname
is substituted:
colname <- "a"
### Using !!colname < 3) ###
rlang::inject(substitute(
df |>
filter(!!colname < 3)
))
# filter(df, "a" < 3) # contains a string "a"
### Using !!as.symbol(colname) < 3) ###
rlang::inject(substitute(
df |>
filter(!!as.symbol(colname) < 3)
))
# filter(df, a < 3) # contains a variable a
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论