あなたはスピードをしたい場合は、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/。
もっとデモ:
1:
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.
上記の実装を持つ2つの重要な注意点がありますそれは正しくNA
Sを処理しません。 Rcppはstd::string
が出てくると、'NA'
に文字列化されているようです。問題のリストコンポーネントを真のNA
に置き換えたラッパーを使ってRlandで簡単に解決できます。
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対応のトラバーサルを使用するためにコア関数の実装を書き直す必要があります。この問題を解決すると、割り当てループの前に1回のショットで各ベクトルを事前に割り当てることができないため、パフォーマンスが大幅に低下する可能性があります。
strsplitN('aΩ',1L);
## [[1]]
## [1] "a" "\xce" "\xa9"
##
strsplit('aΩ','');
## [[1]]
## [1] "a" "Ω"
##
'first'と' last'でもベクトル化された 'substring'を使用してください。 – nicola
それは動作しますが、 'Vectorize(substr)'と同じ問題があります。すなわち、O(N^2)ランタイムです。それはまた、最初の文字列のN/2個のコピーを作成するので、O(N^2)メモリにもなります! –
文字列の文字列がASCIIの場合(または少なくともマルチバイト文字を持たない場合)、 'apply(matrix(charToRaw(ch)、nrow = 2)、2、rawToChar)'を試してみてください'substring'よりも速く、大部分は線形にスケールします。 – nicola