Reputation: 179558
I am trying to write some simple Rcpp code examples. This is remarkably easy with the Rcpp
and inline
packages.
But I am stumped on how to test whether two character elements for equality. The following example compares the first elements of two character vectors. But I can't get it to compile.
What is the trick?
library(Rcpp)
library(inline)
cCode <- '
Rcpp::CharacterVector cx(x);
Rcpp::CharacterVector cy(y);
Rcpp::LogicalVector r(1);
r[0] = (cx[0] == cy[0]);
return(r);
'
cCharCompare <- cxxfunction(signature(x="character", y="character"),
plugin="Rcpp", body=cCode)
cCharCompare("a", "b")
--
The comparison using ==
works perfectly fine if one of the two elements is a constant. The following code compiles and gives expected results:
cCode <- '
Rcpp::CharacterVector cx(x);
Rcpp::LogicalVector r(1);
r[0] = (cx[0] == "a");
return(r);
'
cCharCompareA <- cxxfunction(signature(x="character"), plugin="Rcpp", body=cCode)
cCharCompareA("a")
[1] TRUE
cCharCompareA("b")
[1] FALSE
Upvotes: 17
Views: 5485
Reputation: 17642
The equality operator has been introduced in Rcpp
0.10.4. The implementation looks like this in the string_proxy
class:
bool operator==( const string_proxy& other){
return strcmp( begin(), other.begin() ) == 0 ;
}
So now we can write:
#include <Rcpp.h>
using namespace Rcpp ;
// [[Rcpp::export]]
LogicalVector test( CharacterVector x, CharacterVector y){
Rcpp::LogicalVector r(x.size());
for( int i=0; i<x.size(); i++){
r[i] = (x[i] == y[i]);
}
return(r);
}
And something similar is used on our unit tests:
> test(letters, letters)
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[16] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Upvotes: 18
Reputation: 368519
Very nice (technical) answer by @kohske, but here is something more C++-ish: just compare strings!
library(inline) ## implies library(Rcpp) when we use the plugin
cCode <- '
std::string cx = Rcpp::as<std::string>(x);
std::string cy = Rcpp::as<std::string>(y);
bool res = (cx == cy);
return(Rcpp::wrap(res));
'
cCharCompare <- cxxfunction(signature(x="character", y="character"),
plugin="Rcpp", body=cCode)
cCharCompare("a", "b")
If you really want to compare just the first character of the strings, then you can go from x
to x.c_str()
and either index its initial element, or just dereference the pointer to the first char.
A more R-ish answer could maybe sweep over actual vectors of strings...
Upvotes: 14
Reputation: 66902
Try this:
// r[0] = (cx[0] == cy[0]);
// r[0] = ((char*)cx[0] == (char*)cy[0]); <- this is wrong
r[0] = (*(char*)cx[0] == *(char*)cy[0]); // this is correct.
It is not easy to explain, but
CharacterVector
is not char[]
.operator []
returns StringProxy
.StringProxy
is not a type of char
.StringProxy
has a member operator function char*
that convert StringProxy
to char*
.So, maybe (char*)cx[0]
is a pointer.
Now I forget many things about C++ syntax...
The reason hy the compile fails is the failure of type inference in operator overload ==
for StringProxy
.
Upvotes: 17