Кажется, что некоторые программисты используют:
a = {}
a$foo = 1
a$bar = 2
Какая польза от a = list(foo = 1, bar = 2)
?
Зачем использовать {}
? Это выражение возвращает NULL
, поэтому назначение NULL
будет делать то же самое, не так ли?
Кажется, что некоторые программисты используют:
a = {}
a$foo = 1
a$bar = 2
Какая польза от a = list(foo = 1, bar = 2)
?
Зачем использовать {}
? Это выражение возвращает NULL
, поэтому назначение NULL
будет делать то же самое, не так ли?
Зачем использовать
{}
, это выражение возвращаетNULL
, поэтому назначениеNULL
будет делать то же самое, не так ли?
Да, a <- NULL
дает тот же эффект. Использование {}
скорее всего будет личного стиля.
NULL
NULL
- это, вероятно, самый универсальный и запутанный объект R. Из определения R-языка NULL:
Он используется всякий раз, когда необходимо указать или указать, что объект отсутствует. Его не следует путать с вектором или списком нулевой длины.
Объект
NULL
не имеет типа и не имеет модифицируемых свойств. В R есть только один объект NULL, к которому относятся все экземпляры. Для проверки использованияNULL
is.null
. Вы не можете устанавливать атрибуты вNULL
.
Строго говоря, NULL
- это просто NULL
. И это единственное, что is.null
возвращает TRUE
. Однако, согласно " ?NULL
:
Объекты со значением NULL могут быть изменены операторами замещения и будут привязаны к типу правой части.
Таким образом, хотя он не идентичен вектору length-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")
a <- vector("list", 2); a[[1]] <- 1; a[[2]] <- 2; names(a) <- c("foo", "bar")
a <- vector("list", 2); a[[1]] <- 1; a[[2]] <- 2; names(a) <- c("foo", "bar")
.
Я действительно искал
?mode
, но он не перечисляет возможные режимы. Он указывает на?typeof
который затем указывает на возможные значения, перечисленные в структуре TypeTable вsrc/main/util.c
Мне не удалось найти этот файл даже в папке (OSX). Любая идея, где это найти?
Это означает источник R-дистрибутива, который является файлом ".tar.gz" на CRAN. Альтернативой является поиск 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 }
};
Документация Per R на фигурных скобках и скобках (тип ?'{'
Для их чтения), скобки возвращают последнее выражение, оцениваемое внутри них.
В этом случае a <- {}
существу "возвращает" нулевой объект и поэтому эквивалентен a <- NULL
, который устанавливает пустую переменную, которая затем может рассматриваться как список.
Кстати, именно поэтому можно писать R-функции, в которых выход функции возвращается просто путем записи имени возвращаемой переменной в качестве окончательной команды функции. Например:
function(x) {
y <- x * 2
return(y)
}
Эквивалентно:
function(x) {
y <- x * 2
y
}
Или даже:
function(x) {
y <- x * 2
}
Последняя строка функции, являющейся назначением, подавляет печать результата в консоли, но функция определенно возвращает ожидаемое значение, если оно сохраняется в переменной.