Matt Bannert
Matt Bannert

Reputation: 28274

Assign attributes with C++ to an arbitrary R object?

I have started with Rcpp and I am working through Hadley's book / page here. I guess these basics are more than enough for me, still though I missed, some aspect or feel that this might be less basic:

How can I assign attributes to an arbitrary R Object using C++?

E.g.:

// [[Rcpp::export]]
NumericVector attribs(CharacterVector x,NumericVector y) {
    NumericVector out = y;
    out.attr("my-attr") = x;

    return out;
}

I understand I have to specify the type in C++, but still I wonder whether there's a way to assign an attribute to ANY R object that I pass... I have seen that settatr in the data.table works with C++, but seems to work only with elements of class data.table. Is there any way but writing an extra function for every R mode / class?

EDIT: The ultimate purpose is to speed up assigning attributes to each element of a list. We had discussion here previously – but it did not involve Rcpp so far (except for using it via other packages.)

Upvotes: 3

Views: 459

Answers (2)

Matt Bannert
Matt Bannert

Reputation: 28274

Pardon my enthusiam: It's simply amazing how Rcpp helps an absolute novice to speed up code like that!

That's why I gave it a try though Hadley's answer perfectly covers the question. I tried to turn the input given here into a solution for the more specific case of adding attributes to a list of objects as fast as possible.

Even though my code is probably far from perfect I was already able to outperform all functions suggested in the discussion, including data.table's setattr. I guess this is probably due to the fact that I let C++ not only to do the assignment but the looping as well.

Here's the example and benchmark:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
RObject fx(List x, CharacterVector y){

  int n = x.size();
  NumericVector new_el;  

   for(int i=0; i<n; i++) {
    new_el = x[i];
    new_el.attr("testkey") = y;
    x[i] = new_el;
    }
  return(x);
 }

enter image description here

Upvotes: 0

hadley
hadley

Reputation: 103948

Maybe you want something like this? RObject is the generic class for all R objects. Note the use of clone so that you don't accidentally modify the object passed in.

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
CharacterVector set_attr(CharacterVector x, RObject y) {
  CharacterVector new_x = clone(x);
  new_x.attr("my-attr") = y;

  return new_x;
}


/*** R

x <- c("a", "b", "c")
set_attr(x, 1)
set_attr(x, "a")

attributes(x)

*/

Upvotes: 5

Related Questions