Reputation: 4507
Let's first generate some lists with lists inside:
lappend <- function(lst, ...){
lst <- c(lst, list(...))
return(lst)
}
scalarList <- list()
vectorList <- list()
MatrixList <- list()
for (i in 1:3){
scalarList <- lappend(scalarList,i)
vectorList <- lappend(vectorList,0:i)
MatrixList <- lappend(MatrixList, diag(i + 1))
}
myRList <- list(scalarList = scalarList, vectorList = vectorList,
MatrixList = MatrixList)
Now that our myRList is ready, I'd like to write a function in C++ as follows:
1) inputs: 1) myRList, 2) an id from 1 to 3
2) output: the function should separately print scalar, vector, and matrix corresponding to the input id.
3) There might be many ways to write this function. I specifically want to read-in the list an assign it to a corresponding arma object and then print it. The reason is I wrote this simplified example to learn from you guys on how to extract elements of a list within another list in Rcpp and assign it to an arma object.
Here is my C++ code:
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
// [[Rcpp::export]]
double myListExtractor( Rcpp::List aList_In_R, int id){
int myScalar = Rcpp::as<double>(aList_In_R["scalarList"][id]); //? what to do ?
arma::vec myVector = Rcpp::as<arma::vec>(aList_In_R["vectorList"[id]]); //???
arma::mat myMatrix = Rcpp::as<arma::mat>(aList_In_R["MatrixList"[id]]); //???
// If I manage to do the three assignments above, then printing is easy:
Rcpp::Rcout << "myScalar = " << myScalar << std::endl;
Rcpp::Rcout << "myVector = " << myVector << std::endl;
Rcpp::Rcout << "myMatrix = " << myMatrix << std::endl;
return 1; // we don't care about the return for now
}
Again, I 100% agree that there is no need to assign them to arma objects and then print. In my own code I do lots of algebra with the arma objects and that's the reason I'm emphasizing on this assignment to learn how to fix my code/
Thank you very much in advance for your help. Also, I spent 3 hours browsing the Net and I didn't find any answer.
Upvotes: 3
Views: 2507
Reputation: 21315
Because List
objects don't know anything about the type of objects they contain, you must as
at each level of subsetting. Eg:
int myScalar = Rcpp::as<double>( Rcpp::as<Rcpp::List>(aList_In_R["scalarList"])[id] );
This way, we can signal to the compiler that the slot we're extracting from aList_In_R
is a List
, and all the methods we have for List
s should apply here. It's ugly, but it's an unfortunate consequence on using a statically typed language to operate on objects used in a dynamically typed language.
There is some work on getting templated list containers into Rcpp
that might help with this situation; e.g. instead of having a List
you might have a ListOf< List >
whereby the subset operator would 'know' that it should return List
after subsetting, which could be a bit nicer. Perhaps it could go as deep as ListOf< ListOf< double > >
, etc...
Upvotes: 4