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

Tal Galili tal.galili at gmail.com
Fri Aug 16 07:13:42 CEST 2013


Dear Romain, and other Rcpp-devel members.

I need some help. I've looked into the code Romain posted a few weeks ago,
and I see that I can't change the example from working on double to working
on String.
I keep running into the error of:
no matching function for call to
'range_wrap_dispatch__impl(__gnu_cxx::__normal_iterator<const:Rcpp::String*,str::vector<Rcpp::String>
>& __gnu_cxx__normal_iterator<const Rcpp::String*,std::vector<Rcpp::String>
>& Rcpp::trait::r_type_trait<<Rcpp::String>::r_category)

Any ideas what I might be doing wrong?
(thanks up front)

Here is the code I used in sourceCpp:


////////////////////////////////////
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.
}

String get_label(RObject x){
    String label = x.attr( "label" ) ;
    return label; // either TRUE or FALSE. But often, if it exists - it is
TRUE.
}



//void process( List data, std::vector<double>& results ){
//void process( List data, CharacterVector& results ){
//void process( List data, std::vector<std::string>& results){
void process( List data, std::vector<String>& results ){
    for( int i=0; i<data.size(); i++){
        if( is_list( data[i] ) ){
            // recurse
            process( data[i], results ) ;
        } else if( is_leaf( data[i] ) ){
            // we want to collect them. we can use the NumericVector class
            // wince we know this is a numeric vector.
            // (it is tested in is_leaf)
//            NumericVector y = data[i] ;
//            String x_label = y.attr("label");
            String x_label = get_label(data[i]);


            results.push_back(x_label);
            // loop through the values and add them to the results vector
//            for( int j=0; j<x.size(); j++){
//                results.push_back( x[j] ) ;
//            }
        } // else do nothing
    }
}

// [[Rcpp::export]]
CharacterVector extract_fun(List x){
//    std::vector<double> results ;
    std::vector<String> results ;
    process(x, results) ;
    return wrap(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)

*/






















----------------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 Tue, Jul 23, 2013 at 3:23 PM, Romain Francois
<romain at r-enthusiasts.com>wrote:

> Hello Tal,
>
> I'm trying to express this with the tools available in Rcpp 0.10.3. (And
> adding some tools for later versions too, like is<>).
>
> Here is how I would do the first problem:
>
> First break down into functions. We need :
> - something that tells me if a given R object is a list. With Rcpp devel,
> we could use is<List> but for now we can write it as:
>
> bool is_list(RObject x){
>     return TYPEOF(x) == VECSXP ;
> }
>
> I've added the is<> so that you don't need to know about TYPEOF or VECSXP.
> But here we are essentially mimicking typeof( x ) == "list"
>
> - We need something to tell me if something is a single string:
>
> bool is_string(RObject x){
>     return TYPEOF(x) == STRSXP && Rf_length(x) == 1 ;
> }
>
> agai, with Rcpp devel, we could express this like this: is<String>( x )
> instead.
>
> - We need something that tells if an object has a type attribute that is
> equal to fun. R lets us do that easily, but we have to pay that flexibility
> in C++. What I came up with is this:
>
> bool is_fun(RObject x){
>     // is this a numeric vector
>     if( TYPEOF(x) != REALSXP ) return false ;
>
>     // is the type attribute a string ?
>     if( !is_string( x.attr("type") ) ) return false ;
>
>     // test the string
>     String type = x.attr( "type" ) ;
>     return type == "fun" ;
> }
>
> - Then, we need a recursive function that goes through elements of a list.
> For collecting results, I'm choosing to pass a std::vector by reference. So
> there are two things to learn here:
>    - pass by reference
>    - std::vector
> you'll find many resources online to teach you these things.
>
> void process( List data, std::vector<double>& results ){
>     for( int i=0; i<data.size(); i++){
>         if( is_list( data[i] ) ){
>             // recurse
>             process( data[i], results ) ;
>         } else if( is_fun( data[i] ) ){
>             // we want to collect them. we can use the NumericVector class
>             // wince we know thius is a numeric vector.
>             // (it is tested in is_fun)
>             NumericVector x = data[i] ;
>
>             // loop through the values and add them to the results vector
>             for( int j=0; j<x.size(); j++){
>                 results.push_back( x[j] ) ;
>             }
>         } // else do nothing
>     }
> }
>
>
> - Finally, we need something that you can call from R. It takes a list as
> input, and returns a numeric vector.
>
> // [[Rcpp::export]]
> NumericVector extract_fun(List x){
>     std::vector<double> results ;
>     process(x, results) ;
>     return wrap(results) ;
> }
>
>
> Here is the full script:
>
> #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_fun(RObject x){
>     if( TYPEOF(x) != REALSXP ) return false ;
>     if( !is_string( x.attr("type") ) ) return false ;
>     String type = x.attr( "type" ) ;
>     return type == "fun" ;
> }
>
> void process( List data, std::vector<double>& results ){
>     for( int i=0; i<data.size(); i++){
>         if( is_list( data[i] ) ){
>             // recurse
>             process( data[i], results ) ;
>         } else if( is_fun( data[i] ) ){
>             // we want to collect them. we can use the NumericVector class
>             // wince we know thius is a numeric vector.
>             // (it is tested in is_fun)
>             NumericVector x = data[i] ;
>
>             // loop through the values and add them to the results vector
>             for( int j=0; j<x.size(); j++){
>                 results.push_back( x[j] ) ;
>             }
>         } // else do nothing
>     }
> }
>
> // [[Rcpp::export]]
> NumericVector extract_fun(List x){
>     std::vector<double> results ;
>     process(x, results) ;
>     return wrap(results) ;
> }
>
> /*** R
>
>
> x <- list(a = 1, b = 2, c = list(ca = 3, cb = 4, 5), 6)
> attr(x[[1]], "type") = "fun"
> attr(x[[3]][[1]], "type") = "fun"
> x
>
> extract_fun(x)
>
> */
>
> You should be able to sourceCpp it and get the expected result.
>
>
>
> I let you do 2 and 3 as an exercize with what you learn from this.
> Hints:
> - For 2). you don't need to collect results, so your process can look like
> this:
>
> void process( List data ){
>     // ...
> }
>
> I let you update the body to do what you wanted
>
> - For 3). There are several ways to do this in C++. you could use a
> reference to an int, a static variable within the function. You could even
> use some data that lives in an R environment, using the Environment class.
>
> Whatever you come up with, feel free to share. Those examples are nice
> examples of something that is relatively easy to do when you start to be
> Rcpp fluent, but not so easy otherwise.
>
> Romain
>
>
> Le 20/07/13 18:44, Tal Galili a écrit :
>
>> Hello dear Rcpp users,
>>
>> First - I'd like to say that I took Hadley and Romain's workshop at the
>> useR conference this year, and I am very excited about trying out Rcpp -
>> this project looks AMAZING.
>>
>> Second - this is my first post, and I apologize if my question is too
>> basic. To my defense, I tried looking through this mailing list /
>> googled before asking, and read through Hadley's github chapter on Rcpp.
>>
>> The questions:
>>
>> I am looking to understand better how List objects can be navigated,
>> their elements accessed, and manipulated - using Rcpp.
>>
>> For example, here is an R list object:
>>
>> x <- list(a = 1, b = 2, c = list(ca = 3, cb = 4, 5), 6)
>> attr(x[[1]], "type") = "fun"
>> attr(x[[3]][[1]], "type") = "fun"
>> x
>>
>> I would like to create two types of functions:
>> 1) A function that will go through "x" and will *_RETURN_* all of the
>>
>> elements within it that are of type "fun".
>> In R I would do it like this:
>>
>> return_fun <- function(x) {
>>     fun_nubmers <- numeric()
>>     for(i in seq_along(x)) {
>>        if(class(x[[i]]) == "list") {
>>           fun_nubmers <- c(fun_nubmers, return_fun(x[[i]]))
>>        } else {
>>           if(!is.null(attr(x[[i]], "type"))) {
>>              if(attr(x[[i]], "type") == "fun") fun_nubmers <-
>> c(fun_nubmers, x[[i]])
>>           }
>>        }
>>     }
>>     return fun_nubmers
>> }
>> return_fun(x) # output: 1 3
>>
>> But in Rcpp there are many parts to this R function that I don't know
>> how to do. I don't know how to access the attributes of a sub-element
>> within a List, I don't know how to check if that attribute is null or
>> not, etc. So any suggestions on either reading material (or better yet -
>> an example of how this function might be created in Rcpp would be great.
>>
>>
>> 2) A function that will go through "x" and will *_CHANGE_* all of the
>>
>> elements within it that are of type "fun". For example, adding 1 to them.
>> In R I would do it like this:
>>
>> add1_fun <- function(x) {
>>     for(i in seq_along(x)) {
>>        if(class(x[[i]]) == "list") {
>>           x[[i]] <- add1_fun(x[[i]])
>>        } else {
>>           if(!is.null(attr(x[[i]], "type"))) {
>>              if(attr(x[[i]], "type") == "fun") x[[i]] <- x[[i]] + 1
>>           }
>>        }
>>     }
>>     x
>> }
>> add1_fun(x)
>> return_fun(x) # output: 1 3
>> return_fun(add1_fun(x) ) # output: 2 4
>>
>>
>> 3) Is it possible to work with some "global" variable from within a
>> recursive Rcpp function?
>> For example:
>>
>>
>> count_till_5 <- function() {
>>     if(!exists("global_var")) global_var = 0
>>
>>     if(global_var <5) {
>>        global_var <<- global_var+1
>>        count_till_5()
>>     }
>> }
>> count_till_5()
>> global_var
>>
>> Is there a way to create something like this with Rcpp?
>>
>>
>> Thanks in advance for any help.
>>
>> With regards,
>> Tal
>>
>
> --
> Romain Francois
> Professional R Enthusiast
> +33(0) 6 28 91 30 30
>
> R Graph Gallery: http://gallery.r-enthusiasts.**com<http://gallery.r-enthusiasts.com>
>
> blog:            http://blog.r-enthusiasts.com
> |- http://bit.ly/13SrjxO : highlight 0.4.2
> `- http://bit.ly/10X94UM : Mobile version of the graph gallery
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130816/da687aa3/attachment-0001.html>


More information about the Rcpp-devel mailing list