首页 文章

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

提问于
浏览
580

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

我知道运营商略有不同,正如这个例子所示

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

但这是唯一的区别吗?

7 回答

  • 28

    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 .

  • 565

    当您使用它们在函数调用中设置参数值时,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 = in Architect,Alt - 在RStudio中(选项 - 在macOS下),Shift - (下划线)在emacs ESS中 .


    如果您更喜欢将 = 写入 <- 但希望对公开发布的代码使用更常见的赋值符号(例如,在CRAN上),则可以使用 formatR 包中的tidy_*函数之一自动将 = 替换为 <- .

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

    问题的答案“为什么 x <- y = 5 抛出错误而不是 x <- y <- 5 ?" is "它's down to the magic contained in the parser". R'的语法包含many ambiguous cases必须以某种方式解析 . 解析器选择以不同的顺序解析表达式的位,具体取决于 =<- 被使用 .

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

    其次,如果我们使用前缀表示法进行赋值,则更清楚 . 所以

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

    解析器将_665342解释为

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

    我们可能会期待 x <- y = 5

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

    但实际上它被解释为

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

    这是因为 = 的优先级低于 <- ,如?Syntax帮助页面所示 .

  • 94

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

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

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

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

  • 21

    根据John Chambers的说法,运算符 = 仅允许在"the top level,",这意味着它不允许在像 if 这样的控制结构中,这使得以下编程错误非法 .

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

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

    你可以设法这样做"isolated from surrounding logical structure, by braces or an extra pair of parentheses,"所以 if ((x = 0)) 1 else x 会起作用 .

    http://developer.r-project.org/equalAssign.html

  • 3

    运算符 <-= 分配到评估它们的环境中 . 运算符 <- 可以在任何地方使用,例如,在命令提示符下键入的完整表达式中,或者作为支持的表达式列表中的子表达式之一 .

  • 29

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

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

    ......
    ' - > - >>'向右分配
    '< - << - '赋值(从右到左)
    '='任务(从右到左)
    ...

    但这是唯一的区别吗?

    既然你问的是赋值运算符:是的,那是唯一的区别 . 但是,如果不相信,你会被原谅 . 即使是?assignOps的R文档声称存在更多差异:

    运算符< - 可以在任何地方使用,而operator =只允许在顶层(例如,在命令提示符下键入的完整表达式中)或作为支撑列表中的子表达式之一表达式 .

    让我们不要过分细致: the R documentation is (subtly) wrong [1] . 这很容易显示:我们只需要找到 = 运算符的反例,它不是(a)在顶层,也不是(b)在表达式的支撑列表中的子表达式(即 {…; …} ) . - 无需再费周折:

    x
    # Error: object 'x' not found
    sum((x = 1), 2)
    # [1] 3
    x
    # [1] 1
    

    显然,我们在上下文(a)和(b)之外使用 = 执行了一项任务 . 那么,为什么几十年来核心R语言功能的文档出错呢?

    这是因为在R的语法中,符号 = 有两个不同的含义,这些含义经常混淆:

    • 第一个含义是作为赋值运算符 . 这是我们到目前为止所讨论的全部内容 .

    • 第二个含义不是运算符,而是一个语法标记,表示在函数调用中传递的命名参数 . 与 = 运算符不同,它在运行时不执行任何操作,它只是更改表达式的解析方式 .

    让我们来看看 .

    在一般形式的任何代码中......

    ‹function_name›(‹argname› = ‹value›, …)
    ‹function_name›(‹args›, ‹argname› = ‹value›, …)
    

    ... = 是定义命名参数传递的标记:它不是赋值运算符 . 此外,在某些句法语境中完全禁止 =

    if (‹var› = ‹value›) …
    while (‹var› = ‹value›) …
    for (‹var› = ‹value› in ‹value2›) …
    for (‹var1› in ‹var2› = ‹value›) …
    

    其中任何一个都会在<bla>中引发错误“unexpected'=' .

    在任何其他上下文中, = 指的是赋值运算符调用 . 特别是,仅在子表达式周围加括号使上述(a)中的任何一个有效,(b)赋值 . 例如,以下执行赋值:

    median((x = 1 : 10))
    

    但是也:

    if (! (nf = length(from))) return()
    

    现在你可能反对这样的代码是残暴的(你可能是对的) . 但是我从base :: file.copy函数中取代了这个代码(替换了<--with =) - 它在核心R代码库的大部分内容中都是普遍存在的模式 .

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

    [=赋值]只允许在语法中的两个位置:在顶层(作为完整的程序或用户类型的表达式);当与周围的逻辑结构隔离时,通过括号或一对额外的括号 .


    坦白:我早先撒了谎 . =<- 运算符之间还有一个区别:它们调用不同的函数 . 默认情况下,这些函数执行相同的操作,但您可以单独覆盖它们中的任何一个以更改行为 . 相比之下, <--> (从左到右的赋值)虽然语法上不同,但总是调用相同的函数 . 覆盖一个也会覆盖另一个 . 知道这很难实际but it can be used for some fun shenanigans .

  • 16

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

    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

相关问题