如何在 Rcpp 中连接列表
How to concatenate Lists in Rcpp
我想 c()
Rcpp 中的 2 个列表,但我正在努力获得与 R 中相同的结构。
这里是一些简单的数据+例子:
rlist = list(a = "123")
listadd = list(typ = "fdb")
c(rlist, listadd)
这给了我这个:
$a
[1] "123"
$typ
[1] "fdb"
使用 Rcpp 我只发现 push_back
可以或多或少地做我想做的事情,但结构有点不同。我也尝试基于此 reference 使用 emplace_back
但它似乎没有在 Rcpp 中实现。
cppFunction('
List cLists(List x, List y) {
x.push_back(y);
return(x);
}')
这给了我:
cLists(rlist, listadd)
$a
[1] "123"
[[2]]
[[2]]$typ
[1] "fdb"
基于this question我知道我可以使用Language("c",x,y).eval();
来使用R的c()
函数并得到正确的结果,但这似乎不是正确的方法。
所以我想知道如何正确连接 Rcpp 中的列表?
编辑:
根据@Dirk 的评论,我尝试创建一个新列表并用其他列表元素填充它们,但后来我丢失了元素名称。
cppFunction('
List cLists(List x, List y) {
int nsize = x.size();
int msize = y.size();
List out(nsize + msize);
for(int i = 0; i < nsize; i++) {
out[i] = x[i];
}
for(int i = 0; i < msize; i++) {
out[nsize+i] = y[i];
}
return(out);
}')
输出:
cLists(rlist, listadd)
[[1]]
[1] "123"
[[2]]
[1] "fdb"
这是我想到的。输出是正确的,但不幸的是它的性能也比 R 版本低得多。
library(Rcpp)
cppFunction('
List cLists(List x, List y) {
int nsize = x.size();
int msize = y.size();
List out(nsize + msize);
CharacterVector xnames = x.names();
CharacterVector ynames = y.names();
for(int i = 0; i < nsize; i++) {
out[i] = x[i];
}
for(int i = 0; i < msize; i++) {
out[nsize+i] = y[i];
}
std::vector<std::string> z(x.size() + y.size());
std::copy(xnames.begin(), xnames.end(), z.begin());
std::copy(ynames.begin(), ynames.end(), z.begin() + x.size());
out.attr("names") = z;
return(out);
}')
输出:
cLists(rlist, listadd)
$a
[1] "123"
$typ
[1] "fdb"
您的实施对性能的影响似乎来自将 name
属性复制到 stl 字符串向量。你可以这样避免它:
library(Rcpp)
library(microbenchmark)
cppFunction('
List cLists(List x, List y) {
int nsize = x.size();
int msize = y.size();
List out(nsize + msize);
CharacterVector xnames = x.names();
CharacterVector ynames = y.names();
CharacterVector outnames(nsize + msize);
out.attr("names") = outnames;
for(int i = 0; i < nsize; i++) {
out[i] = x[i];
outnames[i] = xnames[i];
}
for(int i = 0; i < msize; i++) {
out[nsize+i] = y[i];
outnames[nsize+i] = ynames[i];
}
return(out);
}')
x <- as.list(runif(1e6)); names(x) <- sample(letters, 1e6, T)
y <- as.list(runif(1e6)); names(y) <- sample(letters, 1e6, T)
microbenchmark(cLists(x,y), c(x,y), times=3)
Unit: milliseconds
expr min lq mean median uq max neval cld
cLists(x, y) 31.70104 31.86375 32.09983 32.02646 32.29922 32.57198 3 a
c(x, y) 47.31037 53.21409 56.41159 59.11781 60.96220 62.80660 3 b
注意:通过复制到 std::string
,您还会丢失可能的字符编码信息,而仅使用 R/Rcpp 可以保留。
我想 c()
Rcpp 中的 2 个列表,但我正在努力获得与 R 中相同的结构。
这里是一些简单的数据+例子:
rlist = list(a = "123")
listadd = list(typ = "fdb")
c(rlist, listadd)
这给了我这个:
$a [1] "123" $typ [1] "fdb"
使用 Rcpp 我只发现 push_back
可以或多或少地做我想做的事情,但结构有点不同。我也尝试基于此 reference 使用 emplace_back
但它似乎没有在 Rcpp 中实现。
cppFunction('
List cLists(List x, List y) {
x.push_back(y);
return(x);
}')
这给了我:
cLists(rlist, listadd) $a [1] "123" [[2]] [[2]]$typ [1] "fdb"
基于this question我知道我可以使用Language("c",x,y).eval();
来使用R的c()
函数并得到正确的结果,但这似乎不是正确的方法。
所以我想知道如何正确连接 Rcpp 中的列表?
编辑: 根据@Dirk 的评论,我尝试创建一个新列表并用其他列表元素填充它们,但后来我丢失了元素名称。
cppFunction('
List cLists(List x, List y) {
int nsize = x.size();
int msize = y.size();
List out(nsize + msize);
for(int i = 0; i < nsize; i++) {
out[i] = x[i];
}
for(int i = 0; i < msize; i++) {
out[nsize+i] = y[i];
}
return(out);
}')
输出:
cLists(rlist, listadd) [[1]] [1] "123" [[2]] [1] "fdb"
这是我想到的。输出是正确的,但不幸的是它的性能也比 R 版本低得多。
library(Rcpp)
cppFunction('
List cLists(List x, List y) {
int nsize = x.size();
int msize = y.size();
List out(nsize + msize);
CharacterVector xnames = x.names();
CharacterVector ynames = y.names();
for(int i = 0; i < nsize; i++) {
out[i] = x[i];
}
for(int i = 0; i < msize; i++) {
out[nsize+i] = y[i];
}
std::vector<std::string> z(x.size() + y.size());
std::copy(xnames.begin(), xnames.end(), z.begin());
std::copy(ynames.begin(), ynames.end(), z.begin() + x.size());
out.attr("names") = z;
return(out);
}')
输出:
cLists(rlist, listadd)
$a [1] "123" $typ [1] "fdb"
您的实施对性能的影响似乎来自将 name
属性复制到 stl 字符串向量。你可以这样避免它:
library(Rcpp)
library(microbenchmark)
cppFunction('
List cLists(List x, List y) {
int nsize = x.size();
int msize = y.size();
List out(nsize + msize);
CharacterVector xnames = x.names();
CharacterVector ynames = y.names();
CharacterVector outnames(nsize + msize);
out.attr("names") = outnames;
for(int i = 0; i < nsize; i++) {
out[i] = x[i];
outnames[i] = xnames[i];
}
for(int i = 0; i < msize; i++) {
out[nsize+i] = y[i];
outnames[nsize+i] = ynames[i];
}
return(out);
}')
x <- as.list(runif(1e6)); names(x) <- sample(letters, 1e6, T)
y <- as.list(runif(1e6)); names(y) <- sample(letters, 1e6, T)
microbenchmark(cLists(x,y), c(x,y), times=3)
Unit: milliseconds
expr min lq mean median uq max neval cld
cLists(x, y) 31.70104 31.86375 32.09983 32.02646 32.29922 32.57198 3 a
c(x, y) 47.31037 53.21409 56.41159 59.11781 60.96220 62.80660 3 b
注意:通过复制到 std::string
,您还会丢失可能的字符编码信息,而仅使用 R/Rcpp 可以保留。