2013-10-22 35 views
3

通过常规方式(例如ll["name"] <- NULL)从列表中删除元素,会导致整个列表被复制。通常情况下,这是不明显的,直到当然数据集变大。就地删除列表元素

我有一个列表,每个元素的大小在0.25〜2 GB之间。从这个列表中删除三个元素需要大约十分钟的时间来执行(在相对较快的机器上)。

有没有办法从就地删除列表中的元素?


我曾尝试以下:

TEST <- list(A=1:20, B=1:5) 

TEST[["B"]] <- NULL 
TEST["B"] <- NULL 
TEST <- TEST[c(TRUE, FALSE)] 
data.table::set(TEST, "B", value=NULL) # ERROR 

输出,带记忆信息:

cat("\n\n\nATTEMPT 1\n") 
TEST <- list(A=1:20, B=1:5) 
.Internal(inspect(TEST)) 
TEST[["B"]] <- NULL 
.Internal(inspect(TEST)) 

cat("\n\n\nATTEMPT 2\n") 
TEST <- list(A=1:20, B=1:5) 
.Internal(inspect(TEST)) 
TEST["B"] <- NULL 
.Internal(inspect(TEST)) 

cat("\n\n\nATTEMPT 3\n") 
TEST <- list(A=1:20, B=1:5) 
.Internal(inspect(TEST)) 
TEST <- TEST[c(TRUE, FALSE)] 
+1

这是对您可以使用一个环境的应用程序一个存储容器而不是一个列表?如果你做'e < - as.environment(TEST)','rm(“A”,envir = e)'应该比'TEST [“A”] < - NULL'快得多。 (未经测试)。 –

+0

关于复制/修改[**此页**](http://stackoverflow.com/a/16370240/1478381)有一个很好的问题,我链接到这个特定的答案,因为它是非常说明性的,可能值得更多的爱! –

+0

我认为你需要'reflist'作为建议[这里](https://r-forge.r-project.org/tracker/?func=detail&atid=978&aid=2351&group_id=240)。一种可以在列表中工作的方法(类似于'data.table:=/set')。至今尚未实施。 – mnel

回答

2

我不知道你怎么能让一个矢量较短而不复制它。接下来最好的事情是将元素设置为丢失NANULL

根据?Extract,您必须指定TEST[i] <- list(NULL)将元素设置为NULL。我的测试表明i必须是整数或逻辑向量。

> TEST <- list(A=1:20, B=1:5); .Internal(inspect(TEST)) 
@27d2c60 19 VECSXP g0c2 [NAM(1),ATT] (len=2, tl=0) 
    @27dd9e0 13 INTSXP g0c6 [] (len=20, tl=0) 1,2,3,4,5,... 
    @2805c98 13 INTSXP g0c3 [] (len=5, tl=0) 1,2,3,4,5 
ATTRIB: 
    @1f38be8 02 LISTSXP g0c0 [] 
    TAG: @d3f478 01 SYMSXP g1c0 [MARK,LCK,gp=0x4000] "names" (has value) 
    @2807430 16 STRSXP g0c2 [] (len=2, tl=0) 
     @dc2628 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "A" 
     @dc25f8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "B" 
> TEST[2] <- list(NULL); .Internal(inspect(TEST)); TEST 
@27d2c60 19 VECSXP g0c2 [MARK,NAM(1),ATT] (len=2, tl=0) 
    @27dd9e0 13 INTSXP g0c6 [MARK] (len=20, tl=0) 1,2,3,4,5,... 
    @d3fb78 00 NILSXP g1c0 [MARK,NAM(2)] 
ATTRIB: 
    @1f38be8 02 LISTSXP g0c0 [MARK] 
    TAG: @d3f478 01 SYMSXP g1c0 [MARK,LCK,gp=0x4000] "names" (has value) 
    @2807430 16 STRSXP g0c2 [MARK] (len=2, tl=0) 
     @dc2628 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "A" 
     @dc25f8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "B" 
$A 
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

$B 
NULL 
+1

虽然这并不完全相同。 OP想要从列表中删除一个元素;这将保持列表相同,但将其中一个元素设置为NULL。 –

+0

@HongOoi:我想不出一种方法来改变矢量的长度而不复制它。 –

+0

是的,但内部列表只是一个指针向量。人们会认为你可以复制该向量而不复制它指向的所有对象。 –

1

正如@ JoshO'Brien曾建议在他的评论则显得更有效地使用environments而不是lists大对象存储在内存中。根据我的经验,Environments具有显着的时间和内存优势(用于大型物体存储):

元素查找时间。

您是否注意到访问列表末尾的对象可能很慢(几秒钟)?这是因为lists不知道每个元素在内存中的位置,他们必须通过搜索list(我认为)来查找每个元素。

另一方面,在环境中访问变量是即时的(只需要搜索环境中存储的变量名称列表)。这在您的列表元素很大时很明显!

就地修改。

修改(或删除)环境中的变量时,只复制单个对象。当您修改列表时,整个列表将在过程中复制。

与环境

  1. 定义一个新的环境中工作:TEST <- new.env()
  2. 铸造一个环境:TEST <- as.environment(TEST)
  3. 元素的缺失:rm(A, envir=TEST)
  4. 元素创建:TEST$A <- 1:20
  5. 元素访问:存储TEST$A
  6. 清单对象:ls(pos=TEST)(这是names(TEST)等效)
+0

感谢@Manetheran,我广泛使用环境。我正在处理我正在导入的列表对象,所以这不是我可用的选项。 (虽然有帮助的答案+1) –