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

Tal Galili tal.galili at gmail.com
Tue Jul 23 18:35:32 CEST 2013


Thanks Romain and Dirk!
I am currently (slowly) working on developing a package where I would need
some of these skills for specific bottleneck functions. I will get to the
stage of using your code probably in something between 2 to 5 weeks (I
hope).
Once I reach it I will gladly share my progress.

With regards,
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 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/20130723/eaab9a3e/attachment.html>


More information about the Rcpp-devel mailing list