【问题标题】:Overloading `$` for named vector in R在R中为命名向量重载`$`
【发布时间】:2019-11-04 18:40:51
【问题描述】:

使用命名向量时

vec <- c(a = 1, b = 2)

当我应该写vec["a"]vec[["a"]] 来分别访问带名称和不带名称的相应值时,我经常发现自己通过编写vec$a 来引入错误。

我认为 vec$a 是一个错误是违反直觉的,因为 $ 通常会提取命名的东西。这种感觉甚至似乎得到支持,例如在?Extract 中,示例用法是x$name - 这不是非常适合命名 向量吗?

这让我想到了重载 $ 运算符以处理命名向量的可能性。但是,我对 R 中的运算符重载不是很有经验,并且我理解(例如,从答案 here 中)在重载基本运算符时建议谨慎。

我的相互关联的问题:我不明白为什么我不应该像描述的那样超载$?也就是说,是否有(在某种模糊的意义上)一个“好”的理由说明这不是 R 中的默认设置?如果没有,我该如何明智地这样做

我知道在实践中这可能是一个坏主意,如果只是出于便携性的原因,但我仍然很好奇。

【问题讨论】:

  • 您不应该这样做,因为您的代码会让任何确实理解 R 的人感到困惑
  • @akun:我明白这一点,但我很好奇为什么会这样,以及如何改变它。
  • @HongOoi:正如最后一段所建议的那样,我知道这一点,但正如我所说,我很想了解这一点。
  • 我觉得这其实是一个非常有趣的想法,尤其是在将具有命名元素的对象转换为数据框以及反之亦然的上下文中。

标签: r


【解决方案1】:

有时方法重载是件好事;对于原始函数,对于某些类是可行的(例如,data.table:::$&lt;-.data.tabletibble:::$.tbl_df),对于基类来说并非易事。总的来说,我认为尝试这样做是个坏主意。

  • 执行此操作的一种惯用方法是提供支持它的 S3 方法,例如 $.numeric。这将允许您严格控制此方法对特定类型对象的使用(在这种情况下,numeric vector 不会在lists 上触发)。不幸的是,因为$ 是一个原始函数,它不允许重载基础R 对象类,例如$.numeric

  • 如果您愿意对要应用此功能的向量进行重新分类,那么可以完成:

    `$.quux` <- function(x, name) x[name]
    vec <- c(a = 1)
    class(vec) <- c("quux", class(vec))
    vec$a
    # a 
    # 1 
    vec$b
    # <NA> 
    #   NA 
    

    不幸的是,这需要您重新class 任何您希望能够执行此操作的对象。

  • 另一种选择是覆盖 $ 本身:

    `$` <- function(x, name) x[deparse(substitute(name))]
    c(a=1)$a
    # a 
    # 1 
    

    但是这有很多问题:它会影响$ 的所有正常使用,包括非向量参数(尝试mtcars$mpg 并看到它现在返回一个单列@ 987654335@ 而不是向量的正常行为)和赋值(mtcars$mpg &lt;- ... 失败)。当然可以尝试捕捉这些特殊情况中的每一种,但总是会错过一些极端情况、一些对象类型,或者导致一些其他假定的行为行为不端,从而破坏其他东西。

虽然我同意这种行为可能看起来有点不一致,但老实说,有时改变这种行为会产生太多的二阶效应,而无法治愈。 (与这种变化最类似的可能是 python2 与 python3:“过渡”始于 2008 年 12 月,python-3 的第一个版本,尽管 python-2 被称为end-of-life in Jan 2020,但它既不迅速也不顺利。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    相关资源
    最近更新 更多