Skip to content
Prev 6300 / 10988 Next

[Rcpp-devel] Help with accessing and manipulating List objects

Tal,

You were close.  The error you got indicated that some of (our) wrapping
around (our) class String was missing somehow.  String is pretty new; Romain
just added it a few month ago under funding by Hadley -- and I am still
pretty unfamiliar with it.

Which is why I always go back to std::string. So I converted your code back,
which then built find but ran into one run-time error: you didn't test for
the attribute before extracting it.  That is corrected too.  So your
list-walker is below, with some extra verbose stdout prints.

Hope this helps, it is a nice example and always was a very good question.

Dirk


// Code first


#include <Rcpp.h>
using namespace Rcpp;


bool is_list(RObject x){
    return TYPEOF(x) == VECSXP ;
}

bool is_string(RObject x){
    return TYPEOF(x) == STRSXP && Rf_length(x) == 1 ;
}

bool is_logical(RObject x){
    return TYPEOF(x) == LGLSXP && Rf_length(x) == 1 ;
}


bool is_leaf(RObject x){
    if( TYPEOF(x) != REALSXP ) return false ;
    if( !is_logical( x.attr("leaf") ) ) return false ;
    bool leaf = x.attr( "leaf" ) ;
    return leaf; // either TRUE or FALSE. But often, if it exists - it is TRUE.
}

std::string get_label(RObject x){
    std::string label = "<empty>";
    if (x.hasAttribute("label")) {
	label = as<std::string>(x.attr( "label" )) ;
    }
    return label; // either TRUE or FALSE. But often, if it exists - it is TRUE.
}


void process( List data, std::vector<std::string>& results){
    Rcout << "List with " << data.size() << " elements\n";
    for( int i=0; i<data.size(); i++){
        if( is_list( data[i] ) ){
            // recurse
            Rcout << "Recursing into list\n";
            process( data[i], results ) ;
        } else if( is_leaf( data[i] ) ){
            Rcout << "Looking at leaf\n";
            // we want to collect them. we can use the NumericVector class
            // wince we know this is a numeric vector.
            std::string x_label = get_label(data[i]);
            results.push_back(x_label);
        } // else do nothing
    }
}

// [[Rcpp::export]]
std::vector<std::string> extract_fun(List x){
    std::vector<std::string> results ;
    process(x, results) ;
    return(results) ;
}

/*** R

x <- list(a = 1, b = 2, c = list(ca = 3, cb = 4, 5), 6)
attr(x[[1]], "leaf") = TRUE
attr(x[[1]], "label") = "leaf 1"
attr(x[[3]][[1]], "leaf") = TRUE

attr(x[[2]], "leaf") = TRUE
attr(x[[2]], "label") = "leaf 2"

str(x)

extract_fun(x)

*/


// Output below:
List with 4 elements
Looking at leaf
Looking at leaf
Recursing into list
List with 3 elements
Looking at leaf
[1] "leaf 1"  "leaf 2"  "<empty>"