带子串的两个字符向量的差异

时间:2015-10-08 12:51:38

标签: r

我有两个清单:

a <- c("da", "ba", "cs", "dd", "ek")
b <- c("zyc", "ulk", "mae", "csh", "ddi", "dada")

我想从列表b中删除元素,这些元素的子字符串与a中的任何值匹配,例如

grepl("da","dada") # TRUE

你会如何有效地做到这一点?

3 个答案:

答案 0 :(得分:10)

我们可以paste将'a'元素添加到以|作为分隔符的单个字符串,在pattern中将其用作grepl,否定({{1} })子集'b'。

!

答案 1 :(得分:5)

使用简单的for循环的另一个解决方案:

sel <- rep(FALSE, length(b))
for (i in seq_along(a)) {
  sel <- sel | grepl(a[i], b, fixed = TRUE)
}
b[!sel]

不像其他解决方案那样优雅(尤其是akrun的解决方案),但是显示for循环并不总是像人们所认为的那样缓慢:

fun1 <- function(a, b) {
  sel <- rep(FALSE, length(b))
  for (i in seq_along(a)) {
    sel <- sel | grepl(a[i], b, fixed = TRUE)
  }
  b[!sel]
}

fun2 <- function(a, b) {
  b[!apply(sapply(a, function(x) grepl(x,b, fixed=TRUE)),1,sum)]
}

fun3 <- function(a, b) {
  b[-which(sapply(a, grepl, b, fixed=TRUE), arr.ind = TRUE)[, "row"]]
}

fun4 <- function(a, b) {
  b[!grepl(paste(a, collapse="|"), b)]
}

library(stringr)
fun5 <- function(a, b) {
  b[!sapply(b, function(u) any(str_detect(u,a)))]
}

a <- c("da", "ba", "cs", "dd", "ek")
b <- c("zyc", "ulk", "mae", "csh", "ddi", "dada")
b <- rep(b, length.out = 1E3)

library(microbenchmark)
microbenchmark(fun1(a, b), fun2(a, b), fun3(a,b), fun4(a,b), fun5(a,b))


# Unit: microseconds
#       expr       min        lq       mean    median         uq        max neval  cld
# fun1(a, b)   389.630   399.128   408.6146   406.007   411.7690    540.969   100 a   
# fun2(a, b)  5274.143  5445.038  6183.3945  5544.522  5762.1750  35830.143   100   c 
# fun3(a, b)  2568.734  2629.494  2691.8360  2686.552  2729.0840   2956.618   100  b  
# fun4(a, b)   482.585   511.917   530.0885   528.993   541.6685    779.679   100 a   
# fun5(a, b) 53846.970 54293.798 56337.6531 54861.585 55184.3100 132921.883   100    d

答案 2 :(得分:3)

您可以尝试以下方法:

Name

从内部'剥离'此前一个电话,结果如下:首先,从b[!(+(apply(sapply(a, function(x) grepl(x,b)),1,sum)) > 0)] [1] "zyc" "ulk" "mae" 电话(grepl:)获取匹配矩阵:

sapply

请注意,列是sapply(a, function(x) grepl(x,b)) # da ba cs dd ek #[1,] FALSE FALSE FALSE FALSE FALSE #[2,] FALSE FALSE FALSE FALSE FALSE #[3,] FALSE FALSE FALSE FALSE FALSE #[4,] FALSE FALSE TRUE FALSE FALSE #[5,] FALSE FALSE FALSE TRUE FALSE #[6,] TRUE FALSE FALSE FALSE FALSE 的元素,行是a的元素。

然后,b每行的函数和(在apply中,TRUE为1,FALSE为0:

R

注意,这里的行总和可能是&gt; 1(如果有超过1个匹配),所以它必须被强制转换为与前一个调用相关的逻辑:

apply(sapply(a, function(x) grepl(x,b)),1,sum)
#[1] 0 0 0 1 1 1

有了这个,我们可以匹配(+() > 0 )b的索引,但由于我们想要相反,我们使用运算符[

!

正如大卫在评论中所说,这是一种更优雅的方法:

#full code:
step.one <- sapply(a, function(x) grepl(x,b))
step.two <- apply(step.one,1,sum)
step.three <- +(step.two > 0)
step.four <- !step.three
#finally:
b[step.four]