Reputation: 1315
I have the following nested list that I want to loop over using Rcpp:
nested_list <- list("a"=list("a_a","a_b","a_c"),
"b"=list("b_a", "b_b", "b_c"))
Here is my attempt at it:
#include <Rcpp.h>
#include <iostream>
using namespace Rcpp;
// [[Rcpp::export]]
CharacterVector names_get( Rcpp::List y ){
return y.names() ;
}
// [[Rcpp::export]]
void output( Rcpp::List y ){
for(const auto &i : names_get(y))
{
Rcpp::List tmp = y[std::string(i)];
for(const auto &j : integer_names_get(tmp))
std::cout << j << "\n";
}
It compiles fine, but when I run this as output(nested_list)
I get the error Error in output(nested_list) : not compatible with STRSXP
What does this error mean and where/why does it appear?
Upvotes: 2
Views: 1421
Reputation: 4841
I have the following nested list that I want to loop over using Rcpp
Just to add a more elegant solution, you can use these function to either print the names of the nested lists or the elements of the nested lists:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
void print_char_ele(List x) {
for(auto sub_list : x)
for(auto ele : List(sub_list))
for(auto ele_i : CharacterVector(ele))
Rcout << ele_i << '\n';
}
// [[Rcpp::export]]
void print_names(List x) {
for(auto sub_list : x)
for(auto nam : CharacterVector(List(sub_list).names()))
Rcout << nam << '\n';
}
Here is the result of using the two function
nested_list <- list("a" = list("a_a" = "x" , "a_b" = "y" , "a_c" = "z" ),
"b" = list("b_a" = "xx", "b_b" = "yy", "b_c" = "zz"))
print_char_ele(nested_list)
#R> x
#R> y
#R> z
#R> xx
#R> yy
#R> zz
print_names(nested_list)
#R> a_a
#R> a_b
#R> a_c
#R> b_a
#R> b_b
#R> b_c
What does this error mean and where/why does it appear?
As duckmayr mentions, the list you provided do not have any names and you use a function called integer_names_get
which you do not show.
Upvotes: 0
Reputation: 16930
I believe the error is occurring because you are trying to print the names of the sublist when your sublist does not have names:
names(nested_list)
names(nested_list[[1]])
str(nested_list)
> names(nested_list)
[1] "a" "b"
> names(nested_list[[1]])
NULL
> str(nested_list)
List of 2
$ a:List of 3
..$ : chr "a_a"
..$ : chr "a_b"
..$ : chr "a_c"
$ b:List of 3
..$ : chr "b_a"
..$ : chr "b_b"
..$ : chr "b_c"
What you have is a list of two lists, each of which has three unnamed elements that are each a character vector of length one.
An unrelated but nevertheless important issue is that when using Rcpp, you should really use Rcout
rather than cout
; from the Rcpp Gallery:
The Writing R Extensions manual, which provides the gold standard of documentation as far as extending R goes, strongly suggests to use Rprintf and REprintf for output (from C/C++ code). The key reason is that these are matched to the usual output and error streams maintained by R itself.
In fact, use of std::cout and std::cerr (as common in standard C++ code) is flagged when running R CMD check and no longer permitted when uploading to CRAN.
Thanks to an initial patch by Jelmer Ypma, which has since been reworked and extended, we have devices Rcout (for standard output) and Rcerr (for standard error) which intercept output and redirect it to R.
If you really are working with an object like nested_list
and need to get the elements such as "a_a"
, you can try the following (maybe not the most elegant solution, but gets the job done):
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
void output(List x) {
int n = x.size();
for ( int i = 0; i < n; ++i ) {
List sublist = x[i];
int m = sublist.size();
for ( int j = 0; j < m; ++j ) {
CharacterVector sublist_element = sublist[j];
Rcout << sublist_element << "\n";
}
}
}
Which, when called from R on your example object gives the following:
> output(nested_list)
"a_a"
"a_b"
"a_c"
"b_a"
"b_b"
"b_c"
However, if you really are working with a nested list whose sublists have names, like the following:
# Make a nested list with sub-element names:
nested_list2 <- list("a"=list("a_a"=1,"a_b"=2,"a_c"=3),
"b"=list("b_a"=1, "b_b"=2, "b_c"=3))
Your function gave the following output for me (no errors):
a_a
a_b
a_c
b_a
b_b
b_c
but only after I fixed a typo where you call integer_names_get
instead of names_get
and left out the ending curly bracket.
Upvotes: 5