提取两个字符串中不同的字符

8
我有两个字符串,a <- "AERRRTX"; b <- "TRRA"
我想提取在a中未使用的字符,即“ERX”。
我尝试了Extract characters that differ between two strings中的答案,其中使用了setdiff。它返回“EX”,因为b确实有“R”,而setdiff将消除a中所有三个“R”。我的目标是将每个字符视为不同,因此只应消除a中的三个R中的两个。
有什么建议可以替代setdiff,或者其他方法来实现我的输出?
4个回答

11

使用pmatch的不同方法:

a1 <- unlist(strsplit(a, ""))
b1 <- unlist(strsplit(b, "")) 

a1[!1:length(a1) %in% pmatch(b1, a1)]

 #[1] "E" "R" "X"

另一个例子,

a <- "Ronak";b<-"Shah"

a1 <- unlist(strsplit(a, ""))
b1 <- unlist(strsplit(b, ""))
a1[!1:length(a1) %in% pmatch(b1, a1)]

# [1] "R" "o" "n" "k"

1
小问题:建议避免使用 c 这个变量名,因为它是一个常用的内置函数。如果 c 是在任何上层环境中定义的变量,对该标识符的引用可能会绑定到它,这可能会导致很多代码出错。例如,在这种情况下,do.call(c,...) 会失败。 - bgoldst
2
不错的替代方案。您可以用a1[-pmatch(b1, a1)]替换第三行。此外,值得注意的是pmatch的“duplicates.ok = FALSE”参数,它区分了它与match之间的行为差异。 - alexis_laz

4
我们可以使用Reduce(),以成功地从b中找到的每个字符开始逐步消除a中的字符:
a <- 'AERRRTX'; b <- 'TRRA';
paste(collapse='',Reduce(function(as,bc) as[-match(bc,as,nomatch=length(as)+1L)],strsplit(b,'')[[1L]],strsplit(a,'')[[1L]]));
## [1] "ERX"

这将保留a中幸存字符的顺序。
另一种方法是标记每个字符在a中出现的索引,对b执行同样的操作,然后我们可以使用setdiff()函数:
a <- 'AERRRTX'; b <- 'TRRA';
pasteOccurrence <- function(x) ave(x,x,FUN=function(x) paste0(x,seq_along(x)));
paste(collapse='',substr(setdiff(pasteOccurrence(strsplit(a,'')[[1L]]),pasteOccurrence(strsplit(b,'')[[1L]])),1L,1L));
## [1] "ERX"

4
您可以使用vecsets包中的vsetdiff函数。
install.packages("vecsets")
library(vecsets)
a <- "AERRRTX"
b <- "TRRA"  
Reduce(vsetdiff, strsplit(c(a, b), split = ""))
## [1] "E" "R" "X"

3

使用 data.table 包的另一种替代方案:

library(data.table)

x = data.table(table(strsplit(a, '')[[1]]))
y = data.table(table(strsplit(b, '')[[1]]))

dt = y[x, on='V1'][,N:=ifelse(is.na(N),0,N)][N!=i.N,res:=i.N-N][res>0]

rep(dt$V1, dt$res)
#[1] "E" "R" "X"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接