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

Dirk Eddelbuettel edd at debian.org
Fri Aug 16 16:19:17 CEST 2013


Hi Tal,

On 16 August 2013 at 15:48, Tal Galili wrote:
| Hello Dirk,
| Your modifications/corrections are VERY helpful, thank you! (also, thank you
| for the general kind words and ongoing support, they are much appreciated)
| 
| One more question/improvement - is it possible to have it return whatever value
| is inside the "label" attr?

Yes, sure. 
 
| For example, running the following would result in an error:
| 
| /*** R
| x <- list(a = 1, b=2, 6)
| attr(x[[2]], "leaf") = TRUE
| attr(x[[2]], "label") = 2
| extract_fun(x)
| 
| ## output:
| ## Error: expecting a string
| /*
| 
| Is there a way to either coerce/force "2" to become a string / or to return it
| as what it is? (a numeric/double value)?
| I thought that was what
|         label = as<std::string>(x.attr( "label" )) ;
| was doing - but apparently it does not coerce non-string into strings
| 
| 
| Any suggestions?

Am at work and a little pressed for time, so just random thoughts:

  -- R has dynamic typing. An attribute could be 'anything'

  -- C++ is typed. You either must agree with yourself on a type, or do the
     casting. Converting int to string, or vice verse, is pretty common, and
     Google will show you examples.

  -- You could try to combine the approaches and just pick leaf elements and
     stick them into a a List object as SEXP (using wrap(...)).

This is a nice example of a recursize list / tree walker. We'll get it
polished and onto the Rcpp Gallery in no time.

Dirk

| 
| Tal
| 
| 
| 
| 
| 
| 
| 
| 
| 
| 
| ----------------Contact
| Details:-------------------------------------------------------
| Contact me: Tal.Galili at gmail.com| Read me: www.talgalili.com (Hebrew) | www.biostatistics.co.il (Hebrew) |
| www.r-statistics.com (English)
| ----------------------------------------------------------------------------------------------
| 
| 
| 
| On Fri, Aug 16, 2013 at 2:47 PM, Dirk Eddelbuettel <edd at debian.org> wrote:
| 
| 
|     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:
| 
|     > extract_fun(x)
|     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>"
| 
| 
| 
|     --
|     Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com
| 
| 

-- 
Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com


More information about the Rcpp-devel mailing list