r - 为什么有人应该使用 {} 在 R 中初始化一个空对象?
问题描述
似乎有些程序员正在使用:
a = {}
a$foo = 1
a$bar = 2
有什么好处a = list(foo = 1, bar = 2)
?
为什么要{}
使用?这个表达式只返回NULL
,所以NULL
赋值也会做同样的事情,不是吗?
解决方案
您的第一个查询
为什么应该
{}
使用,这个表达式只返回NULL
,所以NULL
赋值也会做同样的事情,不是吗?
是的,a <- NULL
效果相同。使用{}
可能是个人风格。
NULL
NULL
可能是最通用和最令人困惑的 R 对象。从NULL 的 R 语言定义:
每当需要指示或指定对象不存在时使用它。它不应与零长度的向量或列表相混淆。
该
NULL
对象没有类型,也没有可修改的属性。R 中只有一个 NULL 对象,所有实例都引用它。测试NULL
使用is.null
。您不能在 上设置属性NULL
。
严格来说,NULL
只是NULL
。它是唯一is.null
返回的东西TRUE
。但是,根据?NULL
:
值为 NULL 的对象可以通过替换运算符更改,并将强制转换为右侧的类型。
因此,虽然它与具有合法模式的长度为 0 的向量不同(并非 R 中的所有模式都允许在向量中;阅读?mode
模式的完整列表以及?vector
向量的合法性),这种灵活的强制转换通常使其表现得像一个长度为 0 的向量:
## examples of atomic mode
integer(0) ## vector(mode = "integer", length = 0)
numeric(0) ## vector(mode = "numeric", length = 0)
character(0) ## vector(mode = "character", length = 0)
logical(0) ## vector(mode = "logical", length = 0)
## "list" mode
list() ## vector(mode = "list", length = 0)
## "expression" mode
expression() ## vector(mode = "expression", length = 0)
您可以进行矢量连接:
c(NULL, 0L) ## c(integer(0), 0L)
c(NULL, expression(1+2)) ## c(expression(), expression(1+2))
c(NULL, list(foo = 1)) ## c(list(), list(foo = 1))
您可以增长一个向量(就像您在问题中所做的那样):
a <- NULL; a[1] <- 1; a[2] <- 2
## a <- numeric(0); a[1] <- 1; a[2] <- 2
a <- NULL; a[1] <- TRUE; a[2] <- FALSE
## a <- logical(0); a[1] <- TRUE; a[2] <- FALSE
a <- NULL; a$foo <- 1; a$bar <- 2
## a <- list(); a$foo <- 1; a$bar <- 2
a <- NULL; a[1] <- expression(1+1); a[2] <- expression(2+2)
## a <- expression(); a[1] <- expression(1+1); a[2] <- expression(2+2)
用于{}
生成NULL
类似于expression()
. 虽然不完全相同,但当您稍后使用它执行某些操作时,运行时强制确实使它们无法区分。例如,当增加一个列表时,以下任何一个都可以工作:
a <- NULL; a$foo <- 1; a$bar <- 2
a <- numeric(0); a$foo <- 1; a$bar <- 2 ## there is a warning
a <- character(0); a$foo <- 1; a$bar <- 2 ## there is a warning
a <- expression(); a$foo <- 1; a$bar <- 2
a <- list(); a$foo <- 1; a$bar <- 2
对于具有原子模式的长度为 0 的向量,在运行时强制期间会产生警告(因为从“原子”到“递归”的变化太明显了):
#Warning message:
#In a$foo <- 1 : Coercing LHS to a list
我们没有收到表达式设置的警告,因为来自?expression
:
作为模式“表达式”的对象是一个列表......
好吧,它不是通常意义上的“列表”;它是一个类似于列表的抽象语法树。
您的第二个查询
有什么好处
a = list(foo = 1, bar = 2)
?
这样做没有任何好处。您应该已经在其他地方读到,增长对象在 R 中是一种不好的做法。在 Google 上的随机搜索给出:增长对象和循环内存预分配。
如果您知道向量的长度以及每个元素的值,请直接创建它,例如a = list(foo = 1, bar = 2)
.
如果您知道向量的长度,但要计算其元素的值(例如通过循环),请设置一个向量并进行填充,例如a <- vector("list", 2); a[[1]] <- 1; a[[2]] <- 2; names(a) <- c("foo", "bar")
.
回复Tjebo
我实际上查了一下
?mode
,但它没有列出可能的模式。它指向?typeof
which 然后指向结构TypeTable中列出的可能值src/main/util.c
。我什至连文件夹(OSX)都找不到这个文件。知道在哪里可以找到这个吗?
它表示 R 发行版的来源,它是 CRAN 上的“.tar.gz”文件。另一种方法是在https://github.com/wch/r-source上查找。无论哪种方式,这是表格:
TypeTable[] = {
{ "NULL", NILSXP }, /* real types */
{ "symbol", SYMSXP },
{ "pairlist", LISTSXP },
{ "closure", CLOSXP },
{ "environment", ENVSXP },
{ "promise", PROMSXP },
{ "language", LANGSXP },
{ "special", SPECIALSXP },
{ "builtin", BUILTINSXP },
{ "char", CHARSXP },
{ "logical", LGLSXP },
{ "integer", INTSXP },
{ "double", REALSXP }, /*- "real", for R <= 0.61.x */
{ "complex", CPLXSXP },
{ "character", STRSXP },
{ "...", DOTSXP },
{ "any", ANYSXP },
{ "expression", EXPRSXP },
{ "list", VECSXP },
{ "externalptr", EXTPTRSXP },
{ "bytecode", BCODESXP },
{ "weakref", WEAKREFSXP },
{ "raw", RAWSXP },
{ "S4", S4SXP },
/* aliases : */
{ "numeric", REALSXP },
{ "name", SYMSXP },
{ (char *)NULL, -1 }
};
推荐阅读
- vue.js - 在 Vue.js 中从父组件向动态组件传递数据
- mysql - 尝试使用 mysql 秘密引擎插件设置安装在 GCP 上的 Vault 时出错
- intellij-idea - IntelliJ .idea 文件夹是本地更改的一部分,尽管它是在 .gitignore 中定义的
- http-headers - FastCGI+lighttpd+C++:如何访问代码中的 HTTP 标头?
- mysql - MySQL CURSOR 循环在过程中添加了一个额外的循环
- bash - 如何在 bash 脚本中的 source env shell 之后运行命令
- javascript - JsFiddle:库“加载类型”是指库还是我的代码?
- php - 学说:从数据库中生成实体
- c# - 如何在 C# 中模拟文件上传?
- javascript - 在javascript中将函数作为动态函数调用为数组值