避免R和Rcpp之间的列表复制

时间:2017-09-19 13:38:39

标签: r rcpp

假设我有List个元素(< 20),但每个元素都是几个元素的矢量(IntegerVectorNumericvectorCharacterVector) GB。因此我想避免任何副本。

要从我的List中删除元素,我会编写以下Rcpp代码:

void list_remove_element (List x, int i) {
  Rcout << "Size before : " << x.size() << endl;
  x.erase(i);
  Rcout << "Size after : " <<x.size() << endl;
}

Internaly,这段代码有效地擦除了相应的。遗憾的是,在返回此功能后,R中没有出现任何变化:

> u = list(a=1:5, b=3:4, c=5:6)
> list_remove_elements (u, 1)
Size before : 3
Size after : 2
> str(u)
List of 3
 $ a: int [1:5] 1 2 3 4 5
 $ b: int [1:2] 3 4
 $ c: int [1:2] 5 6

据我所知,使用函数增大或缩小Rcpp对象会导致数据从原始对象复制到新对象中。有没有解决方法可以避免这种情况?

编辑:

我也尝试过以下操作:

void list_remove_elements (SEXP x) {
  SET_VECTOR_ELT(x, 1, R_NilValue);
}

自从我得到它后几乎可以工作:

> str(u)
List of 3
 $ a: int [1:5] 1 2 3 4 5
 $ b: NULL
 $ c: int [1:2] 5 6

但我仍然有元素'b',并且不确定这是正确的方法......

2 个答案:

答案 0 :(得分:2)

使用现有列表中的某些元素创建新列表不会复制内容,即

> data <- list( x = rnorm(1e6), y = rnorm(1e6), z = rnorm(1e6) ).   
> pryr::object_size(data)
24 MB
> data2 <- data[ c("x", "y") ]
> pryr::object_size(data2)
16 MB

datadata2分享他们的记忆

> pryr::object_size(data, data2)
24 MB

只有当你的make更改为data2 $ x

时,才会复制内存
> data2$x[1] <- 12
> pryr::object_size( data, data2 )
32 MB

在原始list_remove_element功能中,您只需返回x这将是一个新列表:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
List list_remove_element (List x, int i) {
  x.erase(i);
  return x ;
}


/*** R
  data <- list( x = rnorm(1e6), y = rnorm(1e6), z = rnorm(1e6) )
  data2 <- list_remove_element(data, 1)

  pryr::object_size(data)
  pryr::object_size(data2)
  pryr::object_size(data, data2)
*/

给出:

> Rcpp::sourceCpp('~/Desktop/test.cpp')
>   data <- list( x = rnorm(1e6), y = rnorm(1e6), z = rnorm(1e6) )
>   data2 <- list_remove_element(data, 1)
>   pryr::object_size(data)
24 MB
>   pryr::object_size(data2)
16 MB
>   pryr::object_size(data, data2)
24 MB

答案 1 :(得分:0)

如果您将参数重命名为&#39; List&amp; x&#39;,那么你应该得到理想的结果。

如下所示:

void list_remove_element (List& x, int i) {
  Rcout << "Size before : " << x.size() << endl;
  x.erase(i);
  Rcout << "Size after : " <<x.size() << endl;
}