Java使用不同方式获取两个集合List的交集、补集、并集(相加)、差集(相减)

文章介绍了在Java中如何使用ApacheCommons和Hutool工具包以及StreamAPI和Collection接口的方法来执行集合的并集、交集、补集和差集操作。示例代码详细展示了各种操作的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 明确概念

首先知道几个单词的意思:

并集 = union

交集 = intersection

补集 = complement

析取 = disjunction

减去 = subtract

1.1 并集

对于两个给定集合A、B,由两个集合所有元素构成的集合,叫做A和B的并集。

记作:AUB 读作“A并B”

例:{3,5}U{2,3,4,6}= {2,3,4,5,6}

1.2 交集

对于两个给定集合A、B,由属于A又属于B的所有元素构成的集合,叫做A和B的交集。

记作: A∩B 读作“A交B”

例:A={1,2,3,4,5},B={3,4,5,6,8},A∩B={3,4,5}

1.3 补集

一般地,设S是一个集合,A是S的一个子集,由S中所有不属于A的元素组成的集合,叫做子集A在S中的绝对补集。

记作:∁UA,包括三层含义:

1)A是U的一个子集,即A⊊U;

2)∁UA表示一个集合,且∁UA⊊U;

3)∁UA是由U中所有不属于A的元素组成的集合,∁UA与A没有公共元素,U中的元素分布在这两个集合中。

2 使用apache工具包

2.1 导入依赖

        <!-- apache 集合工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.1</version>
        </dependency>

2.2 代码如下:


    public static final List<String> list1 = Arrays.asList("A", "B", "C", "D", "E", "F", null);
    public static final List<String> list2 = Arrays.asList("1", "2", "3", "D", "E", "F", null);

    /**
     * apache测试方法
     */
    @Test
    public void apacheTest() {
        System.out.println("交集:" + CollectionUtils.intersection(list1, list2)); // 交集
        System.out.println("补集:" + CollectionUtils.disjunction(list1, list2)); // 补集
        System.out.println("并集:" + CollectionUtils.union(list1, list2)); // 并集
        System.out.println("list1的差集:" + CollectionUtils.subtract(list1, list2)); // list1的差集
        System.out.println("list2的差集:" + CollectionUtils.subtract(list2, list1)); // list2的差集
    }

输出:

3 使用hutool工具包

3.1 导入依赖

        <!-- hutool工具类 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.12</version>
        </dependency>

3.2 代码如下:


    public static final List<String> list1 = Arrays.asList("A", "B", "C", "D", "E", "F", null);
    public static final List<String> list2 = Arrays.asList("1", "2", "3", "D", "E", "F", null);

    /**
     * hutool工具类
     */
    @Test
    public void hutoolTest() {
        System.out.println("交集:" + CollectionUtil.intersection(list1, list2)); // 交集
        System.out.println("补集:" + CollectionUtil.disjunction(list1, list2)); // 补集
        System.out.println("并集:" + CollectionUtil.union(list1, list2)); //并集
        System.out.println("list1的差集"+CollectionUtil.subtract(list1,list2));
        System.out.println("list2的差集"+CollectionUtil.subtract(list2,list1));
        System.out.println("list1的差集:" + CollectionUtil.subtractToList(list1, list2));
        System.out.println("list2的差集:" + CollectionUtil.subtractToList(list2, list1));
    }

输出:

3.3 注意

subtract()和subtractToList()作用一样,不过处理方式不同,使用subtract()时,参数不能是Arrays.asList()的结果,否则会报异常,因为Arrays.asList()返回的对象是Arrays.ArrayList,在方法实现里面调用的是AbstractList抽象类里面的removeAll()方法,该方法代码如下:


public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
 
    // ....
 
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }
 
    // ....
}

4 使用stream方式

4.1 代码如下:


    public static final List<String> list1 = Arrays.asList("A", "B", "C", "D", "E", "F", null);
    public static final List<String> list2 = Arrays.asList("1", "2", "3", "D", "E", "F", null);

    /**
     * stream方式
     */
    @Test
    public void streamTest() {
        List<Object> intersection = list1.stream().filter(list2::contains).collect(Collectors.toList());
        System.out.println("交集:" + intersection);

        List<String> subtract1 = list1.stream().filter(s -> !list2.contains(s)).collect(Collectors.toList());
        System.out.println("集合list1的差集:" + subtract1);
        List<String> subtract2 = list2.stream().filter(s -> !list1.contains(s)).collect(Collectors.toList());
        System.out.println("集合list2的差集:" + subtract2);

        List<String> union1 = list1.parallelStream().collect(Collectors.toList());
        List<String> union2 = list2.parallelStream().collect(Collectors.toList());
        union1.addAll(union2);
        List<String> union3 = union1.stream().distinct().collect(Collectors.toList());
        System.out.println("并集:" + union3);
    }

输出:

5 使用Collection接口中的方法

5.1 代码如下:


    public static String[] attr1 = new String[]{"A", "B", "C", "D", "E", "F", null};
    public static String[] attr2 = new String[]{"1", "2", "3", "D", "E", "F", null};

    /**
     * 使用Collection接口中的方法
     */
    @Test
    public void collectionTest() {
        List<String> list1 = new ArrayList<>(Arrays.asList(attr1));
        List<String> list2 = new ArrayList<>(Arrays.asList(attr2));
        list1.retainAll(list2);
        System.out.println("交集:" + list1);

        ArrayList<String> list3 = new ArrayList<>(Arrays.asList(attr1));
        ArrayList<String> list4 = new ArrayList<>(Arrays.asList(attr2));
        Set<Object> set = new HashSet<>();
        set.addAll(list3);
        set.addAll(list4);
        System.out.println("并集:" + set);

        ArrayList<String> list5 = new ArrayList<>(Arrays.asList(attr1));
        ArrayList<String> list6 = new ArrayList<>(Arrays.asList(attr2));
        list5.removeAll(list6);
        System.out.println("集合A的差集:" + list5);
        ArrayList<String> list7 = new ArrayList<>(Arrays.asList(attr1));
        ArrayList<String> list8 = new ArrayList<>(Arrays.asList(attr2));
        list8.removeAll(list7);
        System.out.println("集合B的差集:" + list8);
    }

输出:

<think>嗯,用户问的是如何在Java中计算两个List对象的交集差集。首先,我需要回忆一下Java集合框架的相关知识。记得List和Set是不同的接口,List允许重复元素,有序,而Set不允许重复,无序。不过,进行集合操作的话,可能需要先将List转换成Set,这样更方便处理,尤其是去重的问题。 首先,交集的话,应该是两个集合中都存在的元素。Java的Set接口有retainAll方法,可以修改当前集合只保留包含在指定集合中的元素,也就是交集。但要注意的是,retainAll会直接修改原集合,所以可能需要先复制一份。比如用HashSet的构造方法传入一个List,创建新的Set,然后调用retainAll。 然后是,就是两个集合所有元素的合,去除重复。用Set的addAll方法应该可以,同样需要先转换成Set,将两个List的元素都加进去,自动去重。不过要注意,如果原List有重复元素,是否要保留重复?用户的问题里可能是指数学意义上的集合操作,所以应该是没有重复的,所以用Set是正确的选择。 差集的话,A - B就是A中存在但B中不存在的元素。Set的removeAll方法可以实现,同样需要处理原集合被修改的问题,所以要创建副本。比如用A的副本调用removeAll(B),得到的就是A的差集的话,可能需要确认用户的定义。有时候是相对于某个全的,比如全U中的元素不在A中的部分。但用户这里可能指的是对称差集,也就是两个集合中各自独有的元素,也就是减去交集。或者是否指的是对称差集?如果是的话,可以用交集来组合,或者用addAll然后removeAll交集。或者更简单的方式,先合两个差集。比如A-B和B-A的就是对称差集。这时候可以用两次差集操作,然后合。 不过用户同时提到了,可能需要明确的定义。在集合论中,通常需要指定全,比如A的是U \ A。但用户的问题可能是在两个List之间操作,可能这里的指的是对称差集,也就是异或操作。比如A和B的对称差集,即属于A或属于B但不同时属于两者的元素。这时候需要确认用户的意图,但根据常见的操作,可能用户指的是对称差集。 接下来,需要考虑如何将List转换为Set,因为List可能有重复元素,而集合操作通常处理的是唯一元素。因此,使用Set来操作是合理的,但用户如果需要保留重复元素的话,可能需要不同的处理方式。但根据常规的集合操作,应该是数学上的集合,所以去重是必要的。因此,在代码示例中应该先将List转换为Set,再操作。 然后,考虑到用户可能使用的是Java 8及以上版本,可以使用Stream API来处理,比如用filter和collect来操作,这样可能更简洁。但传统的方法可能更易懂,尤其是对于刚学习的用户来说。比如使用HashSet的构造器,然后调用retainAll、addAll、removeAll等方法。 例如,交集的话,可以这样做: Set<Integer> set1 = new HashSet<>(list1); Set<Integer> set2 = new HashSet<>(list2); set1.retainAll(set2); List<Integer> intersection = new ArrayList<>(set1); 的话,可以创建一个新的HashSet,然后addAll两个set: Set<Integer> unionSet = new HashSet<>(list1); unionSet.addAll(list2); List<Integer> union = new ArrayList<>(unionSet); 差集的话,比如A - B: Set<Integer> differenceSet = new HashSet<>(list1); differenceSet.removeAll(list2); List<Integer> difference = new ArrayList<>(differenceSet); 对称差集的话,可以通过合两个差集: Set<Integer> symmetricDifference = new HashSet<>(list1); symmetricDifference.addAll(list2); // 先 Set<Integer> temp = new HashSet<>(list1); temp.retainAll(list2); // 交集 symmetricDifference.removeAll(temp); // 减去交集得到对称差集 或者更简单的方式,分别计算A-B和B-A,然后合: Set<Integer> aMinusB = new HashSet<>(list1); aMinusB.removeAll(list2); Set<Integer> bMinusA = new HashSet<>(list2); bMinusA.removeAll(list1); aMinusB.addAll(bMinusA); List<Integer> symmetricDifference = new ArrayList<>(aMinusB); 不过这样可能需要两次removeAll操作,但逻辑清晰。 然后,用户可能需要将这些操作封装成工具方法,或者直接使用现有的工具类。比如Apache Commons Collections或Guava库中的方法,但用户可能希望不依赖第三方库,所以应该给出原生Java的实现。 另外,需要考虑null元素的问题,如果List中包含null的话,Set是可以存储null的,但需要注意处理。不过通常这些操作在常规情况下不会有问题。 此外,用户提到的引用中有关于Java的Set集合的特点,比如无序、不重复、无索引,所以在转换List到Set时,元素的顺序可能会丢失,但结果正确性不受影响。如果用户需要保留某种顺序,可能需要使用LinkedHashSet来保持插入顺序,但通常集合操作不保证顺序,所以这点可能需要说明。 总结一下步骤: 1. 交集使用retainAll方法。 2. 使用addAll方法。 3. 差集(A - B):使用removeAll方法。 4. 对称差集):合两个差集。 在代码示例中,应该展示如何将List转换为Set,进行这些操作,然后将结果转换回List(如果需要的话)。同时,注意处理原集合的修改问题,所以每次操作都要创建新的Set对象,避免修改原始数据。 另外,用户的问题可能希望得到的是List结果,所以最终可能需要将Set转换回ArrayList。但需要注意的是,这样得到的List中的元素是无序的,且没有重复。如果原始List允许重复元素,但用户希望集合操作后的结果去重,那么这样处理是正确的。 最后,根据用户提供的引用,其中提到Java中的makeList方法类似于Arrays.asList,所以在示例代码中,可能需要使用Arrays.asList来初始化测试用的List,比如: List<Integer> list1 = Arrays.asList(1,2,3); List<Integer> list2 = Arrays.asList(3,4,5); 然后进行相应的操作,得到交集[3],[1,2,3,4,5],差集A-B[1,2],对称差集[1,2,4,5]。 测试代码的示例需要正确展示这些结果。 此外,用户的问题可能需要充说明,如果原始List中有重复元素,转换到Set后会被去重,所以集合操作的结果也是唯一的元素。例如,如果list1是[1,1,2,3],转换为Set后是[1,2,3],然后进行交集等操作时,重复元素不会影响结果。 在回答中,应该提到使用Set来进行这些操作的原因,即集合操作的核心是处理唯一元素,而List可能包含重复,所以需要转换。同时,如果需要保留重复元素的处理方式,可能需要不同的方法,但这可能超出标准的集合操作,属于列表操作,但用户的问题明确提到的是交集集合操作,所以应该使用Set的方法。 最后,相关问题部分,可以生成关于如何处理包含重复元素的集合操作,或者使用Stream API实现,或者如何保持顺序等。</think>在Java中计算两个`List`对象的集合操作需借助`Set`实现,以下是具体实现方法: --- ### 一、核心操作实现 #### 1. **交集(Intersection)** ```java // 转换为Set去重 Set<T> set1 = new HashSet<>(list1); Set<T> set2 = new HashSet<>(list2); set1.retainAll(set2); // 保留共有元素 List<T> intersection = new ArrayList<>(set1); ``` #### 2. **(Union)** ```java Set<T> unionSet = new HashSet<>(list1); unionSet.addAll(list2); // 合两个集合 List<T> union = new ArrayList<>(unionSet); ``` #### 3. **差集(Difference)** ```java // A - B(A有但B无的元素) Set<T> differenceSet = new HashSet<>(list1); differenceSet.removeAll(list2); // 移除B中存在的元素 List<T> difference = new ArrayList<>(differenceSet); ``` #### 4. **对称差集/(Symmetric Difference)** ```java // (A ∪ B) - (A ∩ B) Set<T> symmetricDiff = new HashSet<>(list1); symmetricDiff.addAll(list2); // Set<T> temp = new HashSet<>(list1); temp.retainAll(list2); // 交集 symmetricDiff.removeAll(temp); // 移除交集元素 List<T> complement = new ArrayList<>(symmetricDiff); ``` --- ### 二、完整代码示例 ```java import java.util.*; public class ListOperations { public static void main(String[] args) { List<Integer> listA = Arrays.asList(1, 2, 3, 3); List<Integer> listB = Arrays.asList(3, 4, 5); // 交集 Set<Integer> intersection = new HashSet<>(listA); intersection.retainAll(listB); System.out.println("交集: " + intersection); // 输出 [3] // Set<Integer> union = new HashSet<>(listA); union.addAll(listB); System.out.println(": " + union); // 输出 [1, 2, 3, 4, 5] // 差集 A-B Set<Integer> differenceAB = new HashSet<>(listA); differenceAB.removeAll(listB); System.out.println("差集 A-B: " + differenceAB); // 输出 [1, 2] // 对称差集) Set<Integer> symmetricDiff = new HashSet<>(listA); symmetricDiff.addAll(listB); Set<Integer> temp = new HashSet<>(listA); temp.retainAll(listB); symmetricDiff.removeAll(temp); System.out.println("对称差集: " + symmetricDiff); // 输出 [1, 2, 4, 5] } } ``` --- ### 三、关键注意事项 1. **去重处理**:`List`转换为`Set`时会自动去重,确保集合操作符合数学定义[^4]。 2. **性能优化**:`HashSet`的查找和删除操作时间复杂度为$O(1)$,适合大规模数据。 3. **顺序问题**:若需保留顺序,可使用`LinkedHashSet`代替`HashSet`。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴名氏.

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值