R函数返回列表与环境

时间:2019-02-05 14:51:58

标签: r performance comparison r-environment

在以下两种情况下,使用一个相对于另一个有什么优点/缺点? Case-I将其输出作为环境返回,而Case-II将其输出作为列表返回。

案例一:

function(x) {
  ret <- new.env()
  ret$x <- x
  ret$y <- x^2
  return(ret)
}

第二种情况:

function(x) {
  ret <- list()
  ret$x <- x
  ret$y <- x^2
  return(ret)
}

1 个答案:

答案 0 :(得分:0)

尽管相似,但返回列表和环境却有所不同。 来自Advanced R

  

通常,环境类似于列表,但有四个重要例外:

     
      
  • 环境中的每个名称都是唯一的。

  •   
  • 环境中的名称没有排序(即,询问环境的第一个元素是什么没有意义)。

  •   
  • 环境有一个父级。

  •   
  • 环境具有参考语义。

  •   
     

从技术上讲,环境由两个部分组成:框架和父环境,该框架包含名称-对象绑定(其行为很像命名列表)。不幸的是,R中不一致使用了“框架”。例如,parent.frame()不能为您提供环境的父框架。相反,它为您提供了调用环境。在调用环境中将对此进行更详细的讨论。

从帮助中:

help(new.env)
  

环境由框架或命名对象的集合以及指向封闭环境的指针组成。最常见的例子是函数调用局部变量的框架。它的外壳是定义功能的环境(除非随后进行了更改)。封闭环境与父框架有所区别:后者(由parent.frame返回)是指函数调用者的环境。由于混淆非常容易,因此最好不要在环境中使用“父母”(尽管存在parent.env函数)。

来自功能文档:

e1 <- new.env(parent = baseenv())  # this one has enclosure package:base.
e2 <- new.env(parent = e1)
assign("a", 3, envir = e1)
ls(e1)
#[1] "a"

但是ls将提供创建的环境:

ls()
#[1] "e1" "e2"

您可以像访问列表一样访问环境对象:

e1$a
#[1] 3

使用功能:

f1 <- function(x) {
   ret <- new.env()
   ret$x <- x
   ret$y <- x^2
   return(ret)
}

res <- f1(2)
res
#<environment: 0x0000021d55a8a3e8>

res$y
#[1] 4

f2 <- function(x) {
   ret <- list()
   ret$x <- x
   ret$y <- x^2
   return(ret)

res2 <- f(2)
res2
#$x
#[1] 2

#$y
#[1] 4

res2$y
#[1] 4

根据microbenchmarking,他们的表现非常相似:

microbenchmark::microbenchmark(
   function(x) {
      ret <- new.env()
      ret$x <- x
      ret$y <- x^2
      return(ret)
   },
   function(x) {
      ret <- list()
      ret$x <- x
      ret$y <- x^2
      return(ret)
   },
   times = 500L
)

#Unit: nanoseconds
#                                                                                 #expr
# function(x) {     ret <- new.env()     ret$x <- x     ret$y <- x^2     #return(ret) }
#    function(x) {     ret <- list()     ret$x <- x     ret$y <- x^2     #return(ret) }
# min lq   mean median  uq  max neval
#   0  1 31.802      1 100  801   500
#   0  1 37.802      1 100 2902   500

并且它们返回相同大小的对象:

object.size(res)
#464 bytes

object.size(res2)
#464 bytes

,您始终可以根据环境(list2env)和反之(as.list)生成列表:

L <- list(a = 1, b = 2:4, p = pi, ff = gl(3, 4, labels = LETTERS[1:3]))
e <- list2env(L)
e$ff
# [1] A A A A B B B B C C C C
#Levels: A B C

as.list(e)
#$ff
# [1] A A A A B B B B C C C C
#Levels: A B C
#
#$p
#[1] 3.141593
#
#$b
#[1] 2 3 4
#
#$a
#[1] 1