如何返回两个列表之间的差异?

81

我有两个数组列表,例如:

List<Date> a;
contains : 10/10/2014, 10/11/2016

List<Date> b;
contains : 10/10/2016

如何对比列表ab,以便返回在b中缺失的值?例如:10/10/2014


1
Guava有一些用于查找差异的工具,但是它是针对Set的,我认为在这里使用removeAll可能更合适。 - user180100
2
复制列表 a。从副本中删除所有在 b 中出现的元素。 - Sotirios Delimanolis
1
https://docs.oracle.com/javase/7/docs/api/java/util/List.html#removeAll%28java.util.Collection%29 - JB Nizet
如果你想要两者之间的排除,CollectionUtil有一个disjunction方法可以返回差异。 - DejaVuSansMono
这可能是指来自Apache Commons Collections的CollectionUtils.subtract; 有关更多详细信息,请参见此答案 - Per Lundberg
12个回答

78
你可以将它们转换为Set集合,然后执行一个集合差异操作。
就像这样:
Set<Date> ad = new HashSet<Date>(a);
Set<Date> bd = new HashSet<Date>(b);
ad.removeAll(bd);

44
removeAll 返回一个布尔值,而非一个集合。 - Lukazoid
5
没错,但当你查看文档时会看到这个布尔值是指“此调用是否导致集合发生更改”。在进行此更改后,你可以访问该集合,你会注意到它具有预期的结果。 - Dennie
12
创建bd HashSet是不必要的。你只需要调用ad.removeAll(b)即可。 - SlavaSt
2
如果bd比ad有更多的元素怎么办?在这种情况下会发生什么? - Shivansh

49

如果你只想在 b 中查找缺失值,可以执行以下操作:

List toReturn = new ArrayList(a);
toReturn.removeAll(b);

return toReturn;

如果您想查找存在于任一列表中的值,可以执行上面的代码两次。使用更改后的列表。


如果它是不可修改的列表,该怎么办? - user1735921
3
既然你创建了一个新列表,这也适用于不可修改的列表。 - Denis Lukenich

36

我想寻找类似的项目,但我希望找到两个列表之间不同的元素(即这两个列表中独特的元素)。

假设我有:

List<String> oldKeys = Arrays.asList("key0","key1","key2","key5");
List<String> newKeys = Arrays.asList("key0","key2","key5", "key6");

我想知道哪些键被添加了,哪些键被删除了,即我想获取(key1, key6)

使用org.apache.commons.collections.CollectionUtils

List<String> list = new ArrayList<>(CollectionUtils.disjunction(newKeys, oldKeys));

结果

["key1", "key6"]

1
你能告诉我相应的Maven仓库吗?我尝试了这个链接 https://mvnrepository.com/artifact/org.apache.commons/commons-collections4/4.4 但似乎不是正确的。 - paradocslover
1
@paradocslover 这是 https://mvnrepository.com/artifact/commons-collections/commons-collections/3.2.2。 - justMe
1
非常感谢!您知道在较新版本的软件包中该函数更名为什么吗? - paradocslover

26
您可以在Java 8的Stream库中使用filter
List<String> aList = List.of("l","e","t","'","s");
List<String> bList = List.of("g","o","e","s","t");

List<String> difference = aList.stream()
    .filter(aObject -> {
        return ! bList.contains(aObject);
      })
    .collect(Collectors.toList());

//more reduced: no curly braces, no return
List<String> difference2 = aList.stream()
    .filter(aObject -> ! bList.contains(aObject))
    .collect(Collectors.toList());
< p > System.out.println(difference); 的输出结果:

< blockquote > < p >[e, t, s]

< /blockquote >

谢谢陌生人! - Teekam Suthar
欢迎 @Teekam Suthar =) - Milton Jacomini Neto

9

1
注意:此方法不以任何方式支持泛型,因此您得到的是一个原始的、未经检查的“Collection”实例。 - Per Lundberg
1
该方法的签名为:public static <O> Collection<O> subtract(Iterable<? extends O> a, Iterable<? extends O> b),根据文档说明:“O - 泛型类型,能够表示输入集合中包含的类型。” - contrapost
你确实是正确的;我的错。我看的是 3.2 版本的类,那里的方法有一个简单的 public static Collection subtract(final Collection a, final Collection b) 签名。很高兴看到在 4.0 版本中对此进行了改进。 - Per Lundberg

6

首先将列表转换为集合。

// create an empty set 
Set<T> set = new HashSet<>(); 

// Add each element of list into the set 
for (T t : list) 
    set.add(t); 

您可以使用 Sets.difference(Set1, Set2),它返回在Set1中存在的额外项。
您可以使用 Sets.difference(Set2, Set1),它返回在Set2中存在的额外项。


哇,不错的解决方案。我从来不知道有这个类。 - Leo DroidCoder

5
使用Stream API,你可以做如下处理:
List<String> aWithoutB = a.stream()
    .filter(element -> !b.contains(element))
    .collect(Collectors.toList());

List<String> bWithoutA = b.stream()
    .filter(element -> !a.contains(element))
    .collect(Collectors.toList());


4

以下是这个问题的通用解决方案。

public <T> List<T> difference(List<T> first, List<T> second) {
    List<T> toReturn = new ArrayList<>(first);
    toReturn.removeAll(second);
    return toReturn;
}

1
那在大多数情况下都会派上用场。谢谢! - Eren E.

1

您可以在underscore-java库中调用Underscore.difference(lists)方法。实时示例

import com.github.underscore.Underscore;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list1 = Arrays.asList(1, 2, 3);
        List<Integer> list2 = Arrays.asList(1, 2);
        List<Integer> list3 = Underscore.difference(list1, list2);
        System.out.println(list3);
        // [3]
    }
}

如果list2也包含一些额外的值,会怎么样呢? list2 = {1,2,4,5}。期望的list3 = {3,4,5}。 - gaurav kumar

1
List<String> l1 = new ArrayList<String>();
l1.add("apple");
l1.add("orange");
l1.add("banana");
l1.add("strawberry");

List<String> l2 = new ArrayList<String>();
l2.add("apple");
l2.add("orange");

System.out.println(l1);
System.out.println(l2);

for (String A: l2) {
  if (l1.contains(A))
    l1.remove(A);
}

System.out.println("output");
System.out.println(l1);

输出:

[apple, orange, banana, strawberry]
[apple, orange]
output
[banana, strawberry]

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