2015-10-08 21 views
2

兩個字符的向量的我有兩個列表:差分以substring

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

我想刪除從表b的元件,其將具有一個子串匹配的任何一箇中,例如,所述值的

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

你會如何有效地做到這一點?

回答

10

我們可以paste的「a」元素以單一的字符串|作爲分隔符,使用它作爲在greplpattern,否定(!)到子集「B」。

b[!grepl(paste(a, collapse="|"), b)] 
+1

我猜不是!grepl也可以使用invert參數。但是:如果包含正則表達式字符(如「。」)會怎麼樣? – oliver13

+0

回答我自己的問題:我在a向量上使用了http://stackoverflow.com/a/14838321/1563867,但我不確定這是做到這一點的最佳方式。 – oliver13

+0

@ oliver13我想你解決了這個問題。如果不是,請考慮提供一些示例和預期輸出。 – akrun

3

你可以嘗試以下方法:

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每行的功能總和(以R,TRUE爲1和FALSE爲0:

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

注意,在這裏,該行資金可能是> 1(如果有超過1場),因此必須將其強制轉換爲邏輯與之前的通話纏:

+() > 0 

有了這個,我們可以匹配([)b的指數,但是因爲我們希望相反,我們請使用t他運營商!

#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] 

正如大衛表示的意見,這是一個更優雅的方式:

b[-which(sapply(a, grepl, b), arr.ind = TRUE)[, "row"]] 
+2

如果你想在這裏使用'sapply','b [-which(sapply(a,grepl,b),arr。ind = TRUE)[,「row」]]''可能會比結合'apply' –

+1

或'b [rowSums(sapply(a,grepl,x = b))== 0]'或者因爲你知道輸出的長度,使用更快的'vapply':'b [rowSums(vapply(a,grepl,x = b,logical(length(b))))== 0]' – thelatemail

+0

這幾乎是我在找的東西for - 但顯然比grepl-way akrun建議的更復雜 – oliver13

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循環並不總是像人們相信的那樣慢:R:

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

是的,微秒基準是毫無意義的,你應該創建一個更大的數據集IMO –