Оптимальный способ изменить список в функции без копирования в R - PullRequest
1 голос
/ 09 апреля 2020

Я пишу пакет, в котором мне нужно изменить большой список с помощью ряда функций. Каковы возможные способы достижения этого?

Я прилагаю свою реализацию, но не уверен, что это оптимально.

##' @export
test <- function(param = TRUE){
  x <- list("a"= data.frame(a1 = c(1,2), a2 = c(1,1)),
            "b"= data.frame(b1 = c(2,3), b2 = c(1,2)))
  message(paste("in test() function, references to x[[1]]:", inspect(x)[["children"]][[1]][["address"]]))
  message(paste("in test() function, references to x[[2]]:", inspect(x)[["children"]][[2]][["address"]]))
  for(name in names(x)) updateList(x, name)
  message(paste("in test() function, post update references to x[[1]]:", inspect(x)[["children"]][[1]][["address"]]))
  message(paste("in test() function, post update references to x[[2]]:", inspect(x)[["children"]][[2]][["address"]]))
  x
}

updateList <- function(x, name){
  message(paste("updateList() references to x[[1]]:", inspect(x)[["children"]][[1]][["address"]]))
  message(paste("updateList() references to x[[2]]:", inspect(x)[["children"]][[2]][["address"]]))
  newdf <- rbind(x[[name]], c(4,4))
  assign("temp", newdf, envir = parent.frame(n = 1))
  with(parent.frame(n = 1), x[[name]] <- temp)
  invisible(NULL)
}

В Console, когда я запускаю test()

> library(pryr)
> test()
in test() function, references to x[[1]]: 0x55d66ce9dd98
in test() function, references to x[[2]]: 0x55d670954508
updateList() references to x[[1]]: 0x55d66ce9dd98
updateList() references to x[[2]]: 0x55d670954508
updateList() references to x[[1]]: 0x55d66fca1688
updateList() references to x[[2]]: 0x55d670954508
in test() function, post update references to x[[1]]: 0x55d66fca1688
in test() function, post update references to x[[2]]: 0x55d66ffb8208
$a
  a1 a2
1  1  1
2  2  1
3  4  4

$b
  b1 b2
1  2  1
2  3  2
3  4  4

Есть ли способ убедиться, что R не копирует? Как узнать, что он создал промежуточные копии?

Как подсказывает @ len-greski, мы можем видеть адрес каждого элемента. Мы видим, что на каждой итерации копируется только один фрейм данных и остальные не.

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

Вы можете определить, копирует ли объект R с помощью pryr::address() и pryr::refs(). Здесь мы добавим message() функции для проверки адреса x в test() и updateList(), чтобы показать, что объекты копируются.

library(pryr)
test <- function(param = TRUE){
     x <- list("a"= data.frame(a1 = c(1,2), a2 = c(1,1)),
               "b"= data.frame(b1 = c(2,3), b2 = c(1,2)))
     message(paste("in test() function, references to x:",c(address(x)," ",refs(x))))
     for(name in names(x)) updateList(x, name)
     message(paste("in test() function, post update references to x:",c(address(x)," ",refs(x))))
     x
}

updateList <- function(x, name){
     message(paste("updateList() references to x:",c(address(x)," ",refs(x))))
     newdf <- rbind(x[[name]], c(4,4))
     assign("temp", newdf, envir = parent.frame(n = 1))
     with(parent.frame(n = 1), x[[name]] <- temp)
     invisible(NULL)
}

... и вывод.

> test()
in test() function, address of x: 0x7fbbcfaf02c8 references: 1
updateList() address of x: 0x7fbbcf696730 references: 0
updateList() address of x: 0x7fbbcf6846c0 references: 0
in test() function, post update address of x: 0x7fbbcfa3d6c8 references: 1
$a
  a1 a2
1  1  1
2  2  1
3  4  4

$b
  b1 b2
1  2  1
2  3  2
3  4  4

> 

Из изменений в адресе x между пре-обновлением и пост-обновлением мы видим, что он копируется.

0 голосов
/ 10 апреля 2020

В R изменение списка приведет к копированию всего списка.

Возможно, вы захотите использовать объект R6, который может изменяться. Вот несколько ресурсов:

...