寻找两个向量之间不重叠的元素

25

我试图识别那些未包含在另一个向量中的元素。例如,在两个向量中,我有:

list.a <- c("James", "Mary", "Jack", "Sonia", "Michelle", "Vincent")

list.b <- c("James", "Sonia", "Vincent")

有没有一种方法可以验证哪些人不重叠?在这个例子中,我希望获得包含Mary、Jack和Michelle的向量结果。

任何建议都将有所帮助!

4个回答

44

有的,有一种方法:

setdiff(list.a, list.b)
# [1] "Mary"     "Jack"     "Michelle"

3
请注意,此组中的所有功能(setdiff、intersect、union等)都会忽略重复项。如果您的列表包含重复值,您需要进行一些调整。实际上,几天前有一个非常好的stackoverflow问题就是针对这个问题的,并且已经得到了很好的回答。但现在我无法找到它了 :-( - Carl Witthoft
1
@CarlWitthoft 如果您查看setdiff的源代码,您会发现很容易修改它以不忽略重复项。 - hadley
@hadley 我发布了一个“灵活”的setdiff版本,供你参考 :-) - Carl Witthoft

38

我认为需要强调的是,被接受的答案只是部分正确的。命令setdiff(list.a, list.b)仅在这些元素包含在第一个参数中的对象时才能找到不重叠的元素!如果你不知道这个行为并且使用了setdiff(list.b, list.a),结果将在本例中为character(0),这会让你得出结论认为没有非重叠元素。

为了举例说明,使用稍微扩展的示例,明显的快速修复方法是:

list.a <- c("James", "Mary", "Jack", "Sonia", "Michelle", "Vincent")
list.b <- c("James", "Sonia", "Vincent", "Iris")

c(setdiff(list.b, list.a), setdiff(list.a, list.b))
# [1] "Iris"     "Mary"     "Jack"     "Michelle" 

1
正是我正在经历的事情。谢谢! - Rafs

4

根据Hadley和我自己的评论,这里是如何允许重复值的扩展回答。

最终编辑:我不建议任何人使用这个方法,因为结果可能与您的预期不符。如果在x中有一个不在y中的重复值,则会看到该值在输出中重复出现。但是:例如,在x中有四个9,在y中有一个9,则所有9都将被删除。人们可能希望保留其中的三个;这需要更加混乱的代码。

mysetdiff<-function (x, y, multiple=FALSE) 
{
    x <- as.vector(x)
    y <- as.vector(y)
    if (length(x) || length(y)) {
        if (!multiple) {
             unique( x[match(x, y, 0L) == 0L])  
              }else  x[match(x, y, 0L) == 0L] 
        } else x
}

Rgames> x
[1]  8  9  6 10  9
Rgames> y
[1] 5 3 8 8 1
Rgames> setdiff(x,y)
[1]  9  6 10
Rgames> mysetdiff(x,y)
[1]  9  6 10
Rgames> mysetdiff(x,y,mult=T)
[1]  9  6 10  9
Rgames> mysetdiff(y,x,mult=T)
[1] 5 3 1
Rgames> setdiff(y,x)
[1] 5 3 1

1
我会将 if 语句的结果存储到临时变量中,并在 !multiple 的情况下对其调用 unique,这样代码更易读。 - Matthew Lundberg

2

一个适用于重复项的简洁语句:

anti_join(data_frame(c(1,1,2,2)), data_frame(c(1,1)))

这将返回数据框{2,2}。然而,在1,1,2,2中的1,2情况下不适用,因为它找到了两次。


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