2011-10-24 30 views
12

Estoy tratando de escribir algunos ejemplos de código Rcpp simples. Esto es notablemente fácil con los paquetes Rcpp y inline.Cómo probar elementos de Rcpp :: CharacterVector para la igualdad?

Pero estoy perplejo sobre cómo probar si dos elementos de carácter para la igualdad. El siguiente ejemplo compara los primeros elementos de dos vectores de caracteres. Pero no puedo hacer que compile.

¿Cuál es el truco?

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") 

-

La comparación utilizando == funciona perfectamente bien si uno de los dos elementos es una constante. El código siguiente se compila y da resultados esperados:

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 
+0

¿Dónde está 'prueba 'definido? – James

+0

¿Por qué configuras las cosas en NULL antes de configurarlas con cxxfunction? – Spacedman

+0

@James Disculpas: debería haber leído 'cx [0] == cy [0]' - editado. – Andrie

Respuesta

11

Muy buena respuesta (técnica) por @kohske, pero aquí hay algo más C++ - ish: ¡simplemente compare las cadenas!

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") 

Si realmente quiere comparar sólo el primer carácter de las cuerdas, a continuación, se puede pasar de x a x.c_str() y, o bien índice de su elemento inicial, o simplemente eliminar la referencia al puntero al primer carácter.

Una respuesta más R-ish tal vez podría barrer sobre vectores reales de cuerdas ...

+0

Gracias por esto, es más útil. Mi pregunta real es, por supuesto, barrer sobre vectores, pero al tratar de llegar al ejemplo reproducible mínimo, me di cuenta de que mi problema es comparar cadenas, es decir, comparar elementos individuales de un CharacterVector. Con este bit resuelto, debería ser sencillo avanzar al uso de las operaciones vectoriales definidas en 'Rcpp :: Sugar'. – Andrie

+0

Antes de ir de lujo con * Rcpp sugar * (no :: aquí ya que no hay clases de Sugar), probaría la vieja escuela con un loop primero. –

+0

Gracias - funciona con loop s. – Andrie

13

Prueba esto:

// 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. 

No es fácil de explicar, pero

  1. CharacterVector no es char[].
  2. operator [] devuelve StringProxy.
  3. StringProxy no es un tipo de char.
  4. StringProxy tiene una función de operador miembro char* que convierte StringProxy en char*.

Por lo tanto, tal vez (char*)cx[0] es un puntero. Ahora me olvido de muchas cosas acerca de la sintaxis de C++ ...

La razón hy falla la compilación es el fracaso de la inferencia de tipos en la sobrecarga de operador == para StringProxy.

+0

+1 Gracias, esto funciona. Y gracias por la explicación. (He intentado varias formas de coerción a 'char', pero la esquiva respuesta fue forzar el uso de' char * '. Sospecho que hay un poco de azúcar' Rcpp' en la línea de 'como (cx [0]) '- con suerte, alguien puede comentar y dar la sintaxis de azúcar' Rcpp' correcta – Andrie

+0

@Andrie La primera versión es incorrecta. La versión actual es correcta. – kohske

12

El operador de igualdad se ha introducido en Rcpp 0.10.4. La puesta en práctica se parece a esto en la clase string_proxy:

bool operator==(const string_proxy& other){ 
    return strcmp(begin(), other.begin()) == 0 ; 
} 

Así que ahora podemos escribir:

#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); 
} 

Y algo similar se utiliza en nuestras pruebas unitarias:

> 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 
+0

Esto es bueno. Ahorrará un montón de copias innecesarias. – Sameer

Cuestiones relacionadas