[РЕДАКТИРОВАТЬ: проблема, связанная с этим обходным решением, была исправлена с R 3.1.0.]
Меня попросили в другом месте опубликовать это как вопрос, ответ на который я ответил.
Когда функция R принимает произвольное количество параметров через многоточие аргументов, общий способ доступа к ним - это использовать list(...)
:
f <- function(...) {
dots <- list(...)
# Let print them out.
for (i in seq_along(dots)) {
cat(i, ": name=", names(dots)[i], "\n", sep="")
print(dots[[i]])
}
}
> f(10, a=20)
1: name=
[1] 10
2: name=a
[1] 20
Тем не менее, R (по версии 3.0) полностью копирует все элементы list
:
> x <- 10
> .Internal(inspect(x))
@10d85ca68 14 REALSXP g0c1 [MARK,NAM(2),TR] (len=1, tl=0) 10
> x2 <- x
> .Internal(inspect(x2)) # Not copied.
@10d85ca68 14 REALSXP g0c1 [MARK,NAM(2),TR] (len=1, tl=0) 10
> y <- list(x)
> .Internal(inspect(y[[1]])) # x was copied to a different address:
@10dd45e88 14 REALSXP g0c1 [MARK,NAM(1),TR] (len=1, tl=0) 10
> z <- list(y)
> .Internal(inspect(z)) # y was deep-copied:
@10d889ed8 19 VECSXP g0c1 [MARK,NAM(1)] (len=1, tl=0)
@10d889f38 19 VECSXP g0c1 [MARK,TR] (len=1, tl=0)
@10d889f68 14 REALSXP g0c1 [MARK] (len=1, tl=0) 10
Вы можете проверить это с помощью tracemem
, если у вас есть профилирование памяти.
Итак, вы хранили большие объекты в list
? Скопировано. Передача их в любую функцию, которая вызывает list(...)
внутри? Скопировано:
> g <- function(...) for (x in list(...)) .Internal(inspect(x))
> g(z) # Copied.
@10dd45e58 19 VECSXP g0c1 [] (len=1, tl=0)
@10dd35fa8 19 VECSXP g0c1 [] (len=1, tl=0)
@10dd36068 19 VECSXP g0c1 [] (len=1, tl=0)
@10dd36158 14 REALSXP g0c1 [] (len=1, tl=0) 10
> g(z) # ...copied again.
@10dd32268 19 VECSXP g0c1 [] (len=1, tl=0)
@10d854c68 19 VECSXP g0c1 [] (len=1, tl=0)
@10d8548d8 19 VECSXP g0c1 [] (len=1, tl=0)
@10d8548a8 14 REALSXP g0c1 [] (len=1, tl=0) 10
Еще не испугался? Попробуйте grep -l "list(\.\.\.)" *.R
в библиотечных источниках R. Моим любимым является mapply
/Map
, который я регулярно вызывал на ГБ данных и задавался вопросом, почему память заканчивается. По крайней мере, lapply
отлично.
Итак, как я могу написать переменную функцию с аргументами ...
и не копировать их?