9

I followed this link

Passing a data frame from-to R and C using .call()

to find the way to access an R data frame inside C. My requirement is the opposite of that. I have a tabular data in C and need to create an R data frame object in C and return it on as SEXP.

For simple R vectors and lists creation, I followed something like in this link

http://adv-r.had.co.nz/C-interface.html

But I am still wondering how to create a dataframe and return from C to R. Considering a dataframe is a list, I tried creating a list and passing it on, but it expectedly gets me a list in R and not a dataframe.

Any help would be appreciated.

Community
  • 1
  • 1
krunalvora
  • 101
  • 5

2 Answers2

15

You may make use of the fact that a data.frame object is a list consisting of atomic vectors, each having the same length, with names, class, and row.names attributes properly set:

library(inline)
f <- cxxfunction(signature(), body='
   SEXP ret, ans1, ans2, cls, nam, rownam;
   PROTECT(ret = Rf_allocVector(VECSXP, 2)); // a list with two elements
   PROTECT(ans1 = Rf_allocVector(INTSXP, 3)); // first column
   PROTECT(ans2 = Rf_allocVector(INTSXP, 3)); // second column
   for (int i=0; i<3; ++i) { // some data
      INTEGER(ans1)[i] = i+1;
      INTEGER(ans2)[i] = -(i+1);
   }
   SET_VECTOR_ELT(ret, 0, ans1);
   SET_VECTOR_ELT(ret, 1, ans2);

   PROTECT(cls = allocVector(STRSXP, 1)); // class attribute
   SET_STRING_ELT(cls, 0, mkChar("data.frame"));
   classgets(ret, cls);

   PROTECT(nam = allocVector(STRSXP, 2)); // names attribute (column names)
   SET_STRING_ELT(nam, 0, mkChar("a"));
   SET_STRING_ELT(nam, 1, mkChar("b"));
   namesgets(ret, nam);

   PROTECT(rownam = allocVector(STRSXP, 3)); // row.names attribute
   SET_STRING_ELT(rownam, 0, mkChar("1"));
   SET_STRING_ELT(rownam, 1, mkChar("2"));
   SET_STRING_ELT(rownam, 2, mkChar("3"));
   setAttrib(ret, R_RowNamesSymbol, rownam);

   UNPROTECT(6);
   return ret;
')

Which yields:

print(f())
##   a  b
## 1 1 -1
## 2 2 -2
## 3 3 -3
gagolews
  • 12,836
  • 2
  • 50
  • 75
  • Not sure your edited comment is correct (and you are pointing to stale code as we're now on GitHub). A data.frame is a list of equal-length vectors, and we create that list before we 'finalize' it as a data.frame. – Dirk Eddelbuettel May 08 '14 at 21:28
6

Obligatory Rcpp example:

// [[Rcpp::export]] 
DataFrame createTwo(){
    IntegerVector v = IntegerVector::create(1,2,3);
    std::vector<std::string> s(3);
    s[0] = "a";
    s[1] = "b";
    s[2] = "c";
    return DataFrame::create(Named("a")=v, Named("b")=s);
}

which will get you a 3x2 data.frame with one char vector and one int vector.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725