2012-11-10 10 views
5

Ich möchte eine Funktion schreiben, die eine 'Zeichenfolge' nacheinander in einen Vektor schneidet. Ich habe eine ziemlich angemessene R-Lösung dafür; Ich denke jedoch, dass das Schreiben des Codes in C/C++ wahrscheinlich schneller wäre. Zum Beispiel würde Ich mag Lage sein, eine Funktion ‚strslice‘ zu schreiben, die wie folgt funktioniert:Slice eine Zeichenfolge bei aufeinanderfolgenden Indizes mit R/Rcpp?

x <- "abcdef" 
strslice(x, 2) ## should return c("ab", "cd", "ef") 

Allerdings bin ich mir nicht sicher, wie Behandlungselemente des ‚CharacterVector‘ in der herumgereicht zu handhaben Rcpp-Code als Zeichenfolgen. Dies ist, was sich vorstellen könnte ich (meinen Mangel an C++/RCPP Wissen Ich bin sicher, dass es ein besserer Ansatz) Arbeit:

f <- rcpp(signature(x="character", n="integer"), ' 
    std::string myString = Rcpp::as<std::string>(x); 
    int cutpoint = Rcpp::as<int>(n); 
    vector<std::string> outString; 
    int len = myString.length(); 
    for(int i=0; i<len/n; i=i+n) { 
    outString.push_back(myString.substr(i,i+n-1)); 
    myString = myString.substr(i+n, len-i*n); 
    } 
    return Rcpp::wrap<Rcpp::CharacterVector>(outString); 
    ') 

Für die Aufzeichnung der entsprechenden R-Code ich habe, ist:

strslice <- function(x, n) { 
    x <- as.data.frame(stringsAsFactors=FALSE, 
         matrix(unlist(strsplit(x, "")), ncol=n, byrow=T) 
) 

    do.call(function(...) { paste(..., sep="") }, x) 

} 

... aber ich denke, zwischen Datenstrukturen herumzuspringen, wird vieles mit sehr großen Strings verlangsamen.

(Alternativ: Gibt es eine Möglichkeit ‚strsplit‘ in Verhalten zu zwingen, wie ich will?)

+0

Sie sollten sich wahrscheinlich das Biostrings-Paket ansehen. –

Antwort

7

ich substring verwenden würde. Etwas wie folgt aus:

strslice <- function(x, n){ 
    starts <- seq(1L, nchar(x), by = n) 
    substring(x, starts, starts + n-1L) 
} 
strslice("abcdef", 2) 
# [1] "ab" "cd" "ef" 

Über Ihre Rcpp Code, vielleicht können Sie die std::vector<std::string> mit der richtigen Größe zuweisen, so dass Sie es vermeiden, Ändern der Größe, die Speicherzuweisungen bedeuten könnte, ... oder vielleicht direkt eine Rcpp::CharacterVector verwenden. Etwas wie folgt aus:

strslice_rcpp <- rcpp(signature(x="character", n="integer"), ' 
    std::string myString = as<std::string>(x); 
    int cutpoint = as<int>(n); 
    int len = myString.length(); 
    int nout = len/cutpoint ; 
    CharacterVector out(nout) ; 
    for(int i=0; i<nout; i++) { 
     out[i] = myString.substr(cutpoint*i, 2) ; 
    } 
    return out ; 
') 
strslice_rcpp("abdcefg", 2) 
# [1] "ab" "cd" "ef" 
+1

Diese Rcpp-Lösung ist blitzschnell. Vielen Dank! –

4

Diese Einzeiler strapplyc aus dem gsubfn Paket verwendet, ist schnell genug, dass RCPP nicht benötigt werden. Hier wenden wir es auf den gesamten Text von James Joyces Ulysses an, der nur ein paar Sekunden dauert:

library(gsubfn) 
joyce <- readLines("http://www.gutenberg.org/files/4300/4300-8.txt") 
joycec <- paste(joyce, collapse = " ") # all in one string 
n <- 2 
system.time(s <- strapplyc(joycec, paste(rep(".", n), collapse = ""))[[1]]) 
Verwandte Themen