2012-11-10 18 views
5

Bir dizgiyi bir diziye sıralı olarak bir dizine bölen bir işlev yazmak istiyorum. Bunun için oldukça uygun bir R çözümüm var; Ancak, C/C++ kodunun yazılmasının daha hızlı olacağına inanıyorum.R/Rcpp ile ardışık göstergelerdeki bir dizgiyi dilimleyin?

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

Ancak etrafında geçti 'CharacterVector' işlnem elemanlarını nasıl ele emin değilim, şu şekildedir: Örneğin, ben çalışan bir işlev 'strslice' yazabilmek istiyorum Rcpp kod dizeleri olarak. Bu benim (Ben daha iyi bir yaklaşım olduğuna eminim C++/Rcpp benim bilgi eksikliği verilen) çalışır olabileceğini hayal şudur:

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); 
    ') 

kayda geçsin sahip karşılık gelen R kodudur:

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

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

} 

... ama veri yapıları arasında dolaşmayı çok çok çok büyük iplerle yavaşlatır.

(Alternatif olarak: istediğim gibi davranıyor içine 'strsplit' zorlamak için bir yol var mı?)

+0

Muhtemelen Biostrings paketine bakmalısınız. –

cevap

7

Ben substring kullanmak. Böyle bir şey: senin Rcpp kodu hakkında

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

, bunu boyutlandırma önlemek, böylece belki, bellek ayırmalarını anlamına gelebilir ki, doğru boyutu ile std::vector<std::string> tahsis edebilirsiniz ... ya da belki doğrudan Rcpp::CharacterVector kullanın. Böyle bir şey: gsubfn paketinden strapplyc kullanarak Bu tek liner yeterince hızlı olduğunu rcpp gerekli olmayabilir olduğunu

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

Bu Rcpp çözümü hızlı yanıyor. Teşekkürler! –

4

. Burada, James Joyce'un Ulysses'in tüm metnine uygulayacağız, ki bu sadece birkaç saniye sürüyor:

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