用R / Rcpp在连续索引处切一个字符串?

时间:2012-11-10 06:22:53

标签: r rcpp

我想编写一个函数,在给定的索引处按顺序将“字符串”切换为向量。我有一个相当充分的R解决方案;但是,我认为用C / C ++编写代码可能会更快。例如,我希望能够编写一个函数'strslice',其操作如下:

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

但是,我不知道如何处理在Rcpp代码中传递的'CharacterVector'元素作为字符串。这是我想象的可能工作(鉴于我缺乏C ++ / Rcpp知识,我确信有更好的方法):

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

对于记录,我所拥有的相应R代码是:

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

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

}

...但是我觉得在数据结构之间跳跃这么多会使用非常大的字符串减慢速度。

(另外:有没有办法强迫'strsplit'按照我的意愿行事?)

2 个答案:

答案 0 :(得分:7)

我会使用substring。像这样:

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

关于您的Rcpp代码,也许您可​​以使用正确的大小分配std::vector<std::string>,这样就可以避免调整大小,这可能意味着内存分配,...或者可能直接使用{{1 }}。像这样:

Rcpp::CharacterVector

答案 1 :(得分:4)

使用gsubfn包中strapplyc的单行内容足够快,可能不需要rcpp。在这里,我们将它应用于詹姆斯乔伊斯的尤利西斯的全文,只需几秒钟:

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