R:提取长度不等的字符串部分

时间:2017-02-22 09:35:14

标签: r string performance apply strsplit

我有一个字符串列表(非常大,数百万行),我想从中提取特定部分。

我首先在分号处拆分字符串然后提取到特定部分。它变得有点复杂,因为有时候有3个,有时是4个段。但我感兴趣的部分总是最后一个和倒数第二个部分。

示例代码:

dataStr = c("secAlways;  secExtr1; secExtr2",
            "secSometimes;  secAlways;  secExtr1; secExtr2",
            "secSometimes;  secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secSometimes;  secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2")

splStr <- strsplit(dataStr, ";")
extr1 <- list()
extr2 <- list()

for (i in 1:length(splStr)) {
  extr1[i] <- head( tail(splStr[[i]], n=2), n=1)
  extr2[i] <- tail(splStr[[i]], n = 1)
}

它有效,但速度太慢了。对于如何更快地实现这一点,我将不胜感激。我怀疑这可能是apply完成的,但我无法绕过它。

如果对this问题可能是一个重复的问题,则会引发该问题。我认为它有点不同,因为我想提取最后两个元素,并且部分的数量不同。另外,我还没有得到vapply的解决方案,而是已经开始研究我的真实样本了。

6 个答案:

答案 0 :(得分:3)

我认为你最好只使用regexp:

sub(".+; (.+?); (.+?)$", "\\2", dataStr)

这将抓住最后一项。

sub(".+; (.+?); (.+?)$", "\\1", dataStr)

这将抓住最后一项之前的项目。

答案 1 :(得分:2)

来自word解决方案的stringr

stringr::word(dataStr, -2, -1,  sep = ';')

然后你可以strsplit将它们作为两个不同的词,即

do.call(rbind, strsplit(trimws(word(dataStr, -2, -1,  sep = ';')), '; '))
#      [,1]       [,2]      
# [1,] "secExtr1" "secExtr2"
# [2,] "secExtr1" "secExtr2"
# [3,] "secExtr1" "secExtr2"
# [4,] "secExtr1" "secExtr2"
# [5,] "secExtr1" "secExtr2"
# [6,] "secExtr1" "secExtr2"
# [7,] "secExtr1" "secExtr2"
# [8,] "secExtr1" "secExtr2"
# [9,] "secExtr1" "secExtr2"
#[10,] "secExtr1" "secExtr2"

答案 2 :(得分:1)

我们可以使用stringivapply

一起加快速度
library(stringi)
vapply(stri_split(dataStr, regex=';\\s*'), function(x) tail(x, 2), character(2))

答案 3 :(得分:0)

这样做可能会更快:

neo4j

答案 4 :(得分:0)

> str_list <- lapply(dataStr, tail, 2)

> do.call(rbind, str_list)


      [,1]                                           
[1,] "secAlways;  secExtr1; secExtr2"               
[2,] "secSometimes;  secAlways;  secExtr1; secExtr2"
[3,] "secSometimes;  secAlways;  secExtr1; secExtr2"
[4,] "secAlways;  secExtr1; secExtr2"               
[5,] "secAlways;  secExtr1; secExtr2"               
[6,] "secAlways;  secExtr1; secExtr2"               
[7,] "secSometimes;  secAlways;  secExtr1; secExtr2"
[8,] "secAlways;  secExtr1; secExtr2"               
[9,] "secAlways;  secExtr1; secExtr2"               
[10,] "secAlways;  secExtr1; secExtr2"  

我不确定这是否有效?

答案 5 :(得分:0)

假设最后一个和最后一个最后一个段总是相同的字符数,可以通过stringi库以下列方式实现。

我还假设你想要两个列表作为输出。

library(stringi)

dataStr = c("secAlways;  secExtr1; secExtr2",
            "secSometimes;  secAlways;  secExtr1; secExtr2",
            "secSometimes;  secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secSometimes;  secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2",
            "secAlways;  secExtr1; secExtr2")

extr1 <- as.list(stringi::stri_sub(dataStr, from=-18, to=-11))
extr2 <- as.list(stringi::stri_sub(dataStr, from= -8))