r - R 中列表元素的惰性求值

标签 r rstudio lazy-evaluation

有没有办法延迟加载列表元素?

我有一个大型数据帧列表,每个数据帧都需要很长时间才能生成和加载。通常,我不会在 session 期间使用所有 data.frames,因此希望它们在我使用它们时延迟生成和加载。我知道我可以使用delayedAssign创建延迟加载的变量,但这不能应用于列表元素。

下面是一个不起作用的可重现示例:

一些需要一段时间才能生成 data.frames 的函数:

slow_fun_1 <- function(){
  cat('running slow function 1 now \n')
  Sys.sleep(1)
  df<-data.frame(x=1:5, y=6:10)
  return(df)
}

slow_fun_2 <- function(){
  cat('running slow function 2 now \n')
  Sys.sleep(1)
  df<-data.frame(x=11:15, y=16:20)
  return(df)
}

方法 1

my_list <- list()
my_list$df_1 <-slow_fun_1()
my_list$df_2 <-slow_fun_2()
# This is too slow. I might not want to use both df_1 & df_2.

方法 2

my_list_2 <- list()
delayedAssign('my_list_2$df_1', slow_fun_1())
delayedAssign('my_list_2$df_2', slow_fun_2())
# Does not work. Can't assign to a list. 
my_list_2 #output is still an empty list.

最佳答案

这是一种可能的解决方案。这不是懒惰的评估。但它会在您需要时计算 data.frame (然后将其缓存,因此仅在第一次进行计算)。您可以使用包 memoise 来实现此目的。例如

slow_fun_1 <- function(){
  cat('running slow function 1 now \n')
  Sys.sleep(1)
  df<-data.frame(x=1:5, y=6:10)
  return(df)
}

slow_fun_2 <- function(){
  cat('running slow function 2 now \n')
  Sys.sleep(1)
  df<-data.frame(x=11:15, y=16:20)
  return(df)
}

library(memoise)

my_list <- list()
my_list$df_1 <-memoise(slow_fun_1)
my_list$df_2 <-memoise(slow_fun_2)

请注意,my_list$df_1等实际上是为您提供data.frames的函数,因此您的用法应如下所示:

> my_list$df_1()
running slow function 1 now 
  x  y
1 1  6
2 2  7
3 3  8
4 4  9
5 5 10
> my_list$df_1()
  x  y
1 1  6
2 2  7
3 3  8
4 4  9
5 5 10
> 

请注意,缓存函数仅在第一次执行实际计算。

更新:如果您想坚持原来的用法而不调用函数,一种方法是基于列表修改数据结构,例如:

library(memoise)

lazy_list <- function(...){
  structure(list(...), class = c("lazy_list", "list"))
}

as.list.lazy_list <- function(x){
  structure(x, class = "list")
}

generator <- function(f){
  structure(memoise(f), class = c("generator", "function"))
}

`$.lazy_list` <- function(lst, name){
  r <- as.list(lst)[[name]]
  if (inherits(r, "generator")) {
    return(r())
  }
  return(r)
}

`[[.lazy_list` <- function(lst, name){
  r <- as.list(lst)[[name]]
  if (inherits(r, "generator")) {
    return(r())
  }
  return(r)
}

lazy1 <- lazy_list(df_1 = generator(slow_fun_1),
                   df_2 = generator(slow_fun_2),
                   df_3 = data.frame(x=11:15, y=16:20))

lazy1$df_1
lazy1$df_1
lazy1$df_2
lazy1$df_2
lazy1$df_3

关于r - R 中列表元素的惰性求值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45015916/

相关文章:

highcharts - gem Lazy High Charts - 馅饼 donut

R:如何在不同的文件中设置断点?

r - 在 R 中,如何将时间戳间隔数据拆分为常规插槽?

r - 在 R 或 Rstudio 中记录带有错误的控制台历史记录

java - 在 R studio 中更改 Java 版本

image - 翻转图像似乎使用惰性评估

clojure - 尝试在 Clojure 中拆分字符串遇到惰性序列问题

r - 以shiny方式输出N张表,其中N取决于数据

r - 为什么 dplyr::mutate 函数给出了错误的答案?

mysql - 查询 Shiny 应用程序 (R) 中的按钮按下