我有一个向量v,其中每个条目是由分号分隔的一个或多个字符串(或可能是字符(0)):
ABC
DEF;ABC;QWE
TRF
character(0)
ABC;GFD
我需要在“;”之后找到包含“ABC”(1,2,5或逻辑向量T,T,F,F,T)的向量索引
我目前正在使用循环如下:
toSelect=integer(0)
for(i in c(1:length(v))){
if(length(v[i])==0) next
words=strsplit(v[i],";")[[1]]
if(!is.na(match("ABC",words))) toSelect=c(toSelect,i)
}
不幸的是,我的矢量有450k条目,所以这需要太长时间。我更喜欢通过执行类似
的操作来创建逻辑矢量toSelect=(!is.na(match("ABC",strsplit(v,";")))
但是由于strsplit返回一个列表,我找不到一种方法来正确格式化strsplit(v,“;”)作为向量(unlist不会这样做,因为它会破坏索引)。有没有人对如何加快这段代码有任何想法?
谢谢!
答案 0 :(得分:4)
使用正则表达式:
v = list("ABC", "DEF;ABC;QWE", "TRF", character(0), "ABC;GFD")
grep("(^|;)ABC($|;)", v)
#[1] 1 2 5
答案 1 :(得分:3)
棘手的部分是处理character(0)
,@ BlueMagister通过用character(1)
替换它来捏造(这允许使用向量,但不允许表示原始问题)。也许
v <- list("ABC", "DEF;ABC;QWE", "TRF", character(0), "ABC;GFD")
v[sapply(v, length) != 0] <- strsplit(unlist(v), ";", fixed=TRUE)
进行字符串拆分。可以在基础R中继续,但我建议使用IRanges包
source("http://bioconductor.org/biocLite.R")
biocLite("IRanges")
安装,然后
library(IRanges)
w = CharacterList(v)
它给出了一个类似于列表的结构,其中所有元素都必须是字符向量。
> w
CharacterList of length 5
[[1]] ABC
[[2]] DEF ABC QWE
[[3]] TRF
[[4]] character(0)
[[5]] ABC GFD
然后可以做一些有趣的事情,比如问“元素成员是否等于ABC”
> w == "ABC"
LogicalList of length 5
[[1]] TRUE
[[2]] FALSE TRUE FALSE
[[3]] FALSE
[[4]] logical(0)
[[5]] TRUE FALSE
或“任何元素成员等于ABC”
> any(w == "ABC")
[1] TRUE TRUE FALSE FALSE TRUE
这将很好地扩展。对于“开箱即用”不支持的操作,策略(计算上便宜)是unlist
然后使用原始CharacterList作为骨架转换为等长矢量然后relist
,例如使用每个成员reverse
:
> relist(reverse(unlist(w)), w)
CharacterList of length 5
[[1]] CBA
[[2]] FED CBA EWQ
[[3]] FRT
[[4]] character(0)
[[5]] CBA DFG
正如@eddi指出的那样,这比grep慢。动机是(a)避免需要制定复杂的正则表达式,同时(b)获得人们可能喜欢对其结构化的其他操作的灵活性。
答案 2 :(得分:2)
将strsplit
与sapply
和%in%
一起使用:
v <- c("ABC","DEF;ABC;QWE","TRF",character(1),"ABC;GFD")
sapply(strsplit(v,";"),function(x) "ABC" %in% x)
#[1] TRUE TRUE FALSE FALSE TRUE