从vector中删除元素的时间在R中出现的时间量

fd3cxomn  于 2023-03-27  发布在  其他
关注(0)|答案(5)|浏览(107)

我想从一个vector中删除元素的时间是它在另一个vector中出现的时间。就像我减去它们一样。假设我想删除的元素的vector中的每个元素也存在于我想删除的主vector中。

a <- c("A", "B", "B", "C", "C", "C")
b <- c("A", "B", "C", "C")

a[! a %in% b] #returns character(0)

#expected result = "B" "C"

我不想使用一个库。我宁愿写一个函数,如果可能的话没有循环。有没有办法做到这一点?提前谢谢你

w41d8nur

w41d8nur1#

这可能不是最有效的,但

Reduce(function(prev, this) {
  ind <- match(this, prev)
  if (length(ind)) prev[-ind[1]] else prev
}, b, init = a)
# [1] "B" "C"

有趣的是,这里有一个非Reduce的变体(通过查看AllanCameron的简单答案得到启发),它保持了顺序,只有在必须保持顺序的情况下,增加的复杂性才是值得的。

finddiff2 <- function(A, B) {
  dict <- split(seq_along(A), A)
  tb <- table(B)
  nms <- intersect(names(tb), A)
  dict[nms] <- Map(tail, dict[nms], -tb[nms])
  A[sort(unlist(dict))]
}
finddiff2(a, b)
# [1] "B" "C"
finddiff2(rev(a), b)
# [1] "C" "B"
finddiff2(c("A","B"), "A")
# [1] "B"

使用较长的a更容易看到保存情况:

a <- rep(c("A","B","C"), times = 4)
finddiff2(a, b)
# [1] "A" "B" "A" "B" "C" "A" "B" "C"
finddiff2(rev(a), b)
# [1] "B" "A" "C" "B" "A" "C" "B" "A"
tjjdgumg

tjjdgumg2#

在base R中,可以使用pmatch

a[-pmatch(b, a, 0)]
[1] "B" "C"

请注意,在上述情况下,如果b中存在a中不存在的值/级别,则需要0
如果b中的所有元素都在a中,则满足以下条件

a[-pmatch(b, a)]
[1] "B" "C"

注意事项

正如@jblood指出的,pmatch只适用于长度小于100的向量

qmelpv7a

qmelpv7a3#

如果你想定义一个简单的函数,你可以这样做:

finddiff <- function(a, b) {
  levs <- unique(c(a, b))
  tab  <- table(factor(a, levs)) - table(factor(b, levs))
  tab  <- abs(tab[tab != 0])
  rep(names(tab), tab)
}

finddiff(a, b)
#> [1] "B" "C"
eulz3vhy

eulz3vhy4#

rowid使用data.table反联接:

library(data.table)
data.table(a, rowid(a))[!data.table(b, rowid(b)), on = .(a = b, V2)][[1]]
#> [1] "B" "C"

在更大的向量上测试它:

set.seed(2041082007)
a <- stringi::stri_rand_strings(2e5, 2)
b <- sample(a, 1e5)
system.time(ab1 <- data.table(a, rowid(a))[!data.table(b, rowid(b)), on = .(a = b, V2)][[1]])
#>    user  system elapsed 
#>    0.00    0.02    0.01

与来自thispmatch解决方案比较答案:

system.time(ab2 <- a[-pmatch(b, a, 0)])
#>    user  system elapsed 
#>   46.53    0.00   46.56

此外,pmatch似乎无法正确处理此问题:

all.equal(ab1, ab2)
#> [1] "Lengths (100000, 196156) differ (string compare on first 100000)"
#> [2] "99979 string mismatches"

pmatch返回的向量比预期的大得多。请获取两个答案之间的差异:

ab12 <- data.table(ab2, rowid(ab2))[!data.table(ab1, rowid(ab1)), on = .(ab2 = ab1, V2)][[1]]

检查ab12的第一个元素发生了什么。

ab12[1]
#> [1] "28"
sum(a == ab12[1])
#> [1] 57
sum(b == ab12[1])
#> [1] 45

“28”在a中出现了57次,在b中出现了45次,所以结果应该有12个“28”的示例,正如反连接返回的那样。

sum(ab1 == ab12[1])
#> [1] 12

然而,pmatch解决方案错误地返回了一个包含56个“28”示例的向量。

sum(ab2 == ab12[1])
#> [1] 56
8ehkhllq

8ehkhllq5#

c <- data.frame(table(a) - table(b))
tidyr::uncount(c, Freq)$a

结果

[1] B C
Levels: A B C

相关问题