R中“=”和“< - ”之间有什么区别?

时间:2009-11-16 12:14:51

标签: r assignment-operator r-faq

R中的赋值运算符=<-之间有什么区别?

我知道运营商略有不同,如本例所示

x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"

但这是唯一的区别吗?

7 个答案:

答案 0 :(得分:611)

当您使用它们在函数调用中设置参数值时,assignment operators的差异会更明显。例如:

median(x = 1:10)
x   
## Error: object 'x' not found

在这种情况下,x在函数范围内声明,因此在用户工作区中不存在。

median(x <- 1:10)
x    
## [1]  1  2  3  4  5  6  7  8  9 10

在这种情况下,x在用户工作区中声明,因此您可以在函数调用完成后使用它。


R社区普遍倾向于使用<-进行分配(功能签名除外)以兼容(非常)旧版本的S-Plus。请注意,空格有助于澄清诸如

之类的情况
x<-3
# Does this mean assignment?
x <- 3
# Or less than?
x < -3

大多数R IDE都有键盘快捷键,可以让<-更容易输入。建筑师中的 Ctrl + = ,RStudio中的 Alt + - Option + <在emacs + ESS中,kbd> - 在macOS下), Shift + - (下划线)。


如果您希望将=写入<-,但希望对公开发布的代码使用更常见的分配符号(例如,在CRAN上),那么您可以使用{{3}之一formatR包中的函数会自动将=替换为<-

library(formatR)
tidy_source(text = "x=1:5", arrow = TRUE)
## x <- 1:5

问题的答案“为什么x <- y = 5抛出错误而不是x <- y <- 5?”是“这取决于解析器中包含的魔力”。 R的语法包含tidy_*,必须以某种方式解析。解析器选择以不同的顺序解析表达式的位,具体取决于是使用=还是<-

要了解正在发生的事情,您需要知道该任务会以静默方式返回已分配的值。您可以通过显式打印更清楚地看到,例如print(x <- 2 + 3)

其次,如果我们使用前缀表示法进行分配,则更清楚。所以

x <- 5
`<-`(x, 5)  #same thing

y = 5
`=`(y, 5)   #also the same thing

解析器将x <- y <- 5解释为

`<-`(x, `<-`(y, 5))

我们可能希望x <- y = 5成为

`<-`(x, `=`(y, 5))

但实际上它被解释为

`=`(`<-`(x, y), 5)

这是因为=的优先级低于<-,如many ambiguous cases帮助页面所示。​​

答案 1 :(得分:97)

Google的R风格指南通过禁止分配“=”来简化问题。不错的选择。

https://google.github.io/styleguide/Rguide.xml

R手册详细介绍了所有5个赋值运算符。

http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html

答案 2 :(得分:31)

x = y = 5相当于x = (y = 5),因为赋值运算符“group”从右到左,有效。含义:将5分配给y,保留数字5;然后将该5分配给x

这与(x = y) = 5不同,后者不起作用!含义:将y的值分配给x,保留y的值;然后分配5,嗯......,到底是什么?

混合使用不同类型的赋值运算符时,<-=更紧密。因此x = y <- 5被解释为x = (y <- 5),这是有道理的。

不幸的是,x <- y = 5被解释为(x <- y) = 5,这种情况不起作用!

请参阅?Syntax?assignOps了解优先级(绑定)和分组规则。

答案 3 :(得分:30)

根据John Chambers的说法,运算符=只允许在“顶级”,这意味着它不允许在if之类的控制结构中,这使得以下编程错误非法。

> if(x = 0) 1 else x
Error: syntax error

正如他所写的那样,“在控制表达式中不允许使用新的赋值形式[=]可以避免编程错误(例如上面的例子),这些错误更可能与运算符相同而不是其他S赋值。”

如果“与周围的逻辑结构,大括号或一对额外的括号隔离”,您可以设法执行此操作,因此if ((x = 0)) 1 else x可以正常工作。

请参阅http://developer.r-project.org/equalAssign.html

答案 4 :(得分:24)

  

R中的赋值运算符=<-有什么区别?

如您的示例所示,=<-的运算符优先级略有不同(确定它们混合在同一表达式中时的求值顺序)。实际上,R中的?Syntax从最高到最低给出了以下运算符优先级表:

…
‘-> ->>’           rightwards assignment
‘<- <<-’           assignment (right to left)
‘=’                assignment (right to left)
…

但这是唯一的区别吗?

由于您要询问赋值运算符:是的,那是唯一的区别。但是,您会相信其他理由。甚至?assignOps的R文档都声称存在更多差异:

  

运算符<-可以在任何地方使用,   而运算符=仅在最高级别(例如,   在命令提示符下键入的完整表达式中)或作为一个   大括号的表达式列表中的子表达式。

我们不要太在意: R文档是(很巧妙)错误 [1] 。这很容易显示:我们只需要找到=运算符的反例,它不是(a)在顶层,也不是(b)在括号列表中的子表达式(即{ {1}})。 -事不宜迟

{…; …}

很明显,我们已经在上下文(a)和(b)之外使用x # Error: object 'x' not found sum((x = 1), 2) # [1] 3 x # [1] 1 进行了分配。那么,为什么几十年来一直错误地记录核心R语言功能的文档?

这是因为在R的语法中,符号=具有两种通常会被混淆的含义:

  1. 第一个含义是作为赋值运算符。到目前为止,我们已经讨论过这一切。
  2. 第二个含义不是运算符,而是一个语法标记,它表示函数调用中命名参数传递。与=运算符不同,它在运行时不执行任何操作,仅改变了表达式的解析方式。

让我们看看。

以任何常规形式的代码...

=

‹function_name›(‹argname› = ‹value›, …) ‹function_name›(‹args›, ‹argname› = ‹value›, …) 是定义命名参数传递的令牌:它不是赋值运算符。此外,在某些语法上下文中,=完全是禁止

=

其中任何一个都会引发错误“ ‹bla›中出现意外'='”。

在任何其他上下文中,if (‹var› = ‹value›) … while (‹var› = ‹value›) … for (‹var› = ‹value› in ‹value2›) … for (‹var1› in ‹var2› = ‹value›) …指的是赋值运算符调用。特别是,仅在子表达式两边加上括号即可使以上(a)以及(b)赋值中的任何一个有效。例如,以下执行分配:

=

而且:

median((x = 1 : 10))

现在您可能会反对这样的代码是残酷的(您可能是正确的)。但是我从if (! (nf = length(from))) return() 函数中获取了这段代码(将base::file.copy替换为<-)—在许多核心R代码库中,这是一种普遍的模式。

R文档可能基于的original explanation by John Chambers实际上正确地解释了这一点:

  

[{=分配]仅在语法的两个位置允许:顶级(作为完整程序或用户键入的表达式);并且通过括号或多余的一对括号与周围的逻辑结构隔离时。


坦白:我早些说谎。 ==运算符之间还有一个另外的区别:它们调用不同的函数。默认情况下,这些功能执行相同的操作,但是您可以分别覆盖其中的任何一个以更改行为。相比之下,<-<-(从左到右的分配)尽管在语法上是不同的,但始终调用 same 函数。覆盖一个也覆盖另一个。知道这一点很少是实用的but it can be used for some fun shenanigans

答案 5 :(得分:22)

运算符<-=分配到评估它们的环境中。运算符<-可以在任何地方使用, ,而运算符=只允许在顶级 (例如,在输入的完整表达式中命令提示符)或作为支持的表达式列表中的子表达式之一。

答案 6 :(得分:5)

这也可以增加对这两个运营商之间差异的理解:

df <- data.frame(
      a = rnorm(10),
      b <- rnorm(10)
)

对于第一个元素,R已经赋值和正确的名称,而第二个元素的名称看起来有点奇怪。

str(df)
# 'data.frame': 10 obs. of  2 variables:
#  $ a             : num  0.6393 1.125 -1.2514 0.0729 -1.3292 ...
#  $ b....rnorm.10.: num  0.2485 0.0391 -1.6532 -0.3366 1.1951 ...

R版本3.3.2(2016-10-31); macOS Sierra 10.12.1