r - 将字符串拆分为固定大小的 block

标签 r string

这似乎是一个非常简单的任务,但我在 base R 中找不到好的解决方案。我有一个包含 2N 个字符的字符串。如何将其拆分为长度为 N 的字符向量,每个元素都是一个 2 个字符的字符串?

我可以将 substrVectorize 结合使用:

vss <- Vectorize(substr, c("start", "stop"))
ch <- paste(rep("a", 1e6), collapse="")
vss(ch, seq(1, nchar(ch), by=2), seq(2, nchar(ch), by=2))

但这对于长字符串来说真的很慢(我相信是 O(N^2))。

最佳答案

如果你想要速度,Rcpp总是一个不错的选择:

library(Rcpp);
cppFunction('
    List strsplitN(std::vector<std::string> v, int N ) {
        if (N < 1) throw std::invalid_argument("N must be >= 1.");
        List res(v.size());
        for (int i = 0; i < v.size(); ++i) {
            int num = v[i].size()/N + (v[i].size()%N == 0 ? 0 : 1);
            std::vector<std::string> resCur(num,std::string(N,0));
            for (int j = 0; j < num; ++j) resCur[j].assign(v[i].substr(j*N,N));
            res[i] = resCur;
        }
        return res;
    }
');

ch <- paste(rep('a',1e6),collapse='');
system.time({ res <- strsplitN(ch,2L); });
##    user  system elapsed
##   0.109   0.015   0.121
head(res[[1L]]); tail(res[[1L]]);
## [1] "aa" "aa" "aa" "aa" "aa" "aa"
## [1] "aa" "aa" "aa" "aa" "aa" "aa"
length(res[[1L]]);
## [1] 500000

有用的引用:http://gallery.rcpp.org/articles/strings_with_rcpp/ .


更多演示:

strsplitN(c('abcd','efgh'),2L);
## [[1]]
## [1] "ab" "cd"
##
## [[2]]
## [1] "ef" "gh"
##
strsplitN(c('abcd','efgh'),3L);
## [[1]]
## [1] "abc" "d"
##
## [[2]]
## [1] "efg" "h"
##
strsplitN(c('abcd','efgh'),1L);
## [[1]]
## [1] "a" "b" "c" "d"
##
## [[2]]
## [1] "e" "f" "g" "h"
##
strsplitN(c('abcd','efgh'),5L);
## [[1]]
## [1] "abcd"
##
## [[2]]
## [1] "efgh"
##
strsplitN(character(),5L);
## list()
strsplitN(c('abcd','efgh'),0L);
## Error: N must be >= 1.

上面的实现有两个重要的警告:

1:它没有正确处理 NA。当 Rcpp 被迫给出一个 std::string 时,它似乎将字符串化为 'NA'。您可以在 Rland 中使用一个包装器轻松解决此问题,该包装器将有问题的列表组件替换为真正的 NA

x <- c('a',NA); strsplitN(x,1L);
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "N" "A"
##
x <- c('a',NA); ifelse(is.na(x),NA,strsplitN(x,1L));
## [[1]]
## [1] "a"
##
## [[2]]
## [1] NA
##

2:它不能正确处理多字节字符。这是一个更棘手的问题,需要重写核心函数实现才能使用 Unicode 感知遍历。解决这个问题也会导致显着的性能损失,因为您无法在分配循环之前一次性预分配每个向量。

strsplitN('aΩ',1L);
## [[1]]
## [1] "a"    "\xce" "\xa9"
##
strsplit('aΩ','');
## [[1]]
## [1] "a" "Ω"
##

关于r - 将字符串拆分为固定大小的 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36232407/

相关文章:

r - 努力模块化我 Shiny 的应用程序

mysql - 在 ruby​​ 中替换数字后的每个\n

Python 字符串,默认编码和解码(UTF-8?)

r - 使用打破平局的排序,最大限度地减少 bool 字段的不连续性

r - 构建 R 包 : no visible global function definition for 'subject'

python - 使用 pandas 中的另一列替换一列中的值的有效方法

java - 我是否必须在两侧的每个 `trim()` 比较中使用 `String` ?

R:当电子邮件有多个域名后缀时,如何将电子邮件拆分为多个部分?

删除 R 中的常量列

r - 在 R 中将 RDFa 提取为 RDF-XML