Ben Asked: 2025-02-19 16:32:51 +0800 CST2025-02-19 16:32:51 +0800 CST 2025-02-19 16:32:51 +0800 CST 删除多个向量中的重复项 772 我想删除多个向量中的所有重复项,不留下任何重复项。例如,对于这些向量: a <- c("dog", "fish", "cow") b <- c("dog", "horse", "mouse") c <- c("cat", "sheep", "mouse") 预期结果是: a <- c("fish", "cow") b <- c("horse") c <- c("cat", "sheep") 有没有办法实现这一点,而无需连接向量并再次拆分它们? 7 个回答 Voted Best Answer tmfmnk 2025-02-19T16:38:37+08:002025-02-19T16:38:37+08:00 你或许可以这样做: vec <- c(a, b, c) sapply(list(a, b, c), function(x) x[!x %in% vec[duplicated(vec)]]) [[1]] [1] "fish" "cow" [[2]] [1] "horse" [[3]] [1] "cat" "sheep" 如果需要全局环境中的单独变量,可以添加lst()from tibble: vec <- c(a, b, c) l <- sapply(lst(a, b, c), function(x) x[!x %in% vec[duplicated(vec)]]) list2env(l, envir = .GlobalEnv) ThomasIsCoding 2025-02-19T16:41:10+08:002025-02-19T16:41:10+08:00 给定列表中的数据,例如lst <- list(a = a, b = b, c = c),你可以尝试 选项 1 > unstack(subset(stack(lst), ave(seq_along(values), values, FUN = length) == 1)) $a [1] "fish" "cow" $b [1] "horse" $c [1] "cat" "sheep" 选项 2 > lapply(seq_along(lst), \(k) setdiff(lst[[k]], unlist(lst[-k]))) [[1]] [1] "fish" "cow" [[2]] [1] "horse" [[3]] [1] "cat" "sheep" 选项 3 > v <- names(which(table(unlist(lst)) == 1)) > lapply(lst, intersect, v) $a [1] "fish" "cow" $b [1] "horse" $c [1] "cat" "sheep" Maël 2025-02-19T17:34:23+08:002025-02-19T17:34:23+08:00 还有另一种可能性collapse::fduplicated(x, all = TRUE)。与基本 R 的 不同duplicated,此函数允许您包含所有出现多次的值: lst <- list(a = a, b = b, c = c) unstack(subset(stack(lst), !collapse::fduplicated(values, all = TRUE))) # $a # [1] "fish" "cow" # # $b # [1] "horse" # # $c # [1] "cat" "sheep" 对长度为 10 的 100 个元素的列表进行基准测试:我使用的答案collapse是最快的(显示相对时间)。@Friede 的基本 R 答案同样快。 expression min median itr/sec mem_alloc n_itr 1 tmfmnk 5.51 5.95 445.47 44.72 10 2 Tic1 2.87 3.06 879.08 2.12 10 3 Tic2 27.05 26.28 98.60 59.35 10 4 Tic3 4.43 4.28 504.72 2.78 10 5 jay.sf 2931.20 2785.01 1.00 5925.16 10 6 Edward 28.03 27.67 98.86 56.71 10 7 Maël 1.00 1.00 2699.28 1.00 10 8 Friede 1.03 1.00 2568.27 1.25 10 代码: lst <- lapply(setNames(as.list(replicate(100, sample(combn(letters, m = 2, paste, collapse = ""), size = 10, replace = TRUE), simplify = FALSE)), paste0('A', 1:100)), c) vec <- unlist(lst, use.names = FALSE) bench::mark( tmfmnk = sapply(lst, function(x) x[!x %in% vec[duplicated(vec)]]), Tic1 = unstack(subset(stack(lst), ave(seq_along(values), values, FUN = length) == 1)), Tic2 = lapply(seq_along(lst), \(k) setdiff(lst[[k]], unlist(lst[-k]))), Tic3 = {v <- names(which(table(unlist(lst)) == 1)) lapply(lst, intersect, v)}, jay.sf = outer(seq_along(lst), seq_along(lst), Vectorize(\(i, j) setdiff(lst[[i]], unlist(lst[-j])))) |> diag(), Edward = lapply(seq_along(lst), \(x) lst[[x]][!lst[[x]] %in% unlist(lst[setdiff(seq_along(lst)[-x], x)])]), Maël = unstack(subset(stack(lst), !collapse::fduplicated(values, all = TRUE))), Friede = unstack(subset(stack(lst), !duplicated(values) & !duplicated(values, fromLast=TRUE))), check = FALSE, iterations = 10, relative = TRUE ) Friede 2025-02-19T18:23:09+08:002025-02-19T18:23:09+08:00 答题聚会迟到了。 基地R,做!duplicated()两次。 unstack(subset(stack(l), !duplicated(values) & !duplicated(values, fromLast=TRUE))) $a [1] "fish" "cow" $b [1] "horse" $c [1] "cat" "sheep" 这避免了*apply-函数,Vectorize()(即mapply())和outer()。 数据 l = list(a = c("dog", "fish", "cow"), b = c("dog", "horse", "mouse"), c = c("cat", "sheep", "mouse")) Edward 2025-02-19T17:01:16+08:002025-02-19T17:01:16+08:00 lst <- list(a,b,c) lapply(seq_along(lst), \(x) lst[[x]][!lst[[x]] %in% unlist(lst[setdiff(seq_along(lst)[-x], x)])]) [[1]] [1] "fish" "cow" [[2]] [1] "horse" [[3]] [1] "cat" "sheep" 此解决方案将重复项保留在同一个向量中,并且仅当重复项存在于多个向量中时才将其删除,如问题所述。例如,将函数应用于 a <- c("dog", "fish", "dog") b <- c("cow", "horse", "mouse") c <- c("cat", "sheep", "mouse") lst <- list(a,b,c); lst 给出 [[1]] [1] "dog" "fish" "dog" [[2]] [1] "cow" "horse" [[3]] [1] "cat" "sheep" 而其他答案则给出 [[1]] [1] "fish" [[2]] [1] "cow" "horse" [[3]] [1] "cat" "sheep" jay.sf 2025-02-19T17:19:19+08:002025-02-19T17:19:19+08:00 使用setdiff.给出结果outer。diag > lst <- list(a, b, c) > outer(seq_along(lst), seq_along(lst), + Vectorize(\(i, j) setdiff(lst[[i]], unlist(lst[-j])))) |> + diag() [[1]] [1] "fish" "cow" [[2]] [1] "horse" [[3]] [1] "cat" "sheep" Roland 2025-02-20T14:02:36+08:002025-02-20T14:02:36+08:00 如果“重复”的概念适用,这些向量实际上是一个数据集。你应该把它们放在一个数据结构中,并创建“整洁的数据”。我建议使用包 data.table,特别是如果你的数据集很大: library(data.table) DT <- data.table(a, b, c) DT <- melt(DT, measure.vars = 1:3) 然后您可以轻松删除重复的值。 DT[!duplicated(value) & !duplicated(value, fromLast = TRUE)] # variable value # <fctr> <char> #1: a fish #2: a cow #3: b horse #4: c cat #5: c sheep 这种方法假设您的数据集不是太大以至于该variable列的内存需求不成问题。
你或许可以这样做:
如果需要全局环境中的单独变量,可以添加
lst()
fromtibble
:给定列表中的数据,例如
lst <- list(a = a, b = b, c = c)
,你可以尝试还有另一种可能性
collapse::fduplicated(x, all = TRUE)
。与基本 R 的 不同duplicated
,此函数允许您包含所有出现多次的值:对长度为 10 的 100 个元素的列表进行基准测试:我使用的答案
collapse
是最快的(显示相对时间)。@Friede 的基本 R 答案同样快。代码:
答题聚会迟到了。
基地R,做
!duplicated()
两次。这避免了
*apply
-函数,Vectorize()
(即mapply()
)和outer()
。数据
此解决方案将重复项保留在同一个向量中,并且仅当重复项存在于多个向量中时才将其删除,如问题所述。例如,将函数应用于
给出
而其他答案则给出
使用
setdiff
.给出结果outer
。diag
如果“重复”的概念适用,这些向量实际上是一个数据集。你应该把它们放在一个数据结构中,并创建“整洁的数据”。我建议使用包 data.table,特别是如果你的数据集很大:
然后您可以轻松删除重复的值。
这种方法假设您的数据集不是太大以至于该
variable
列的内存需求不成问题。