Как объединить списки в Rcpp - PullRequest
0 голосов
/ 05 июня 2019

Я хочу c() 2 списков в Rcpp, но я изо всех сил пытаюсь получить ту же структуру, что и в R.

Вот несколько простых данных + пример:

rlist = list(a = "123")
listadd = list(typ = "fdb")
c(rlist, listadd)

, что дает мне это:

$a
[1] "123"

$typ
[1] "fdb"

С Rcpp я обнаружил, что push_back только делает более или менее то, что я хочу, но структура немного другая.Я также пытался использовать 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"

Исходя из этого вопроса Я знаю, что мог бы использовать 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"

Ответы [ 2 ]

1 голос
/ 05 июня 2019

Кажется, что снижение производительности вашей реализации связано с копированием атрибута 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.

0 голосов
/ 05 июня 2019

Это то, что я придумал.Вывод правильный, но, к сожалению, он также намного менее производительный, чем версия 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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...