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

blog:            http://blog.r-enthusiasts.com
|- http://bit.ly/13SrjxO : highlight 0.4.2
`- http://bit.ly/10X94UM : Mobile version of the graph gallery

_______________________________________________
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel

Reply via email to