[Java基础] 如何对List进行(交集/并集/补集)运算

本文介绍了如何使用Java原生方法实现List的交集、并集和补集运算,强调了在操作过程中需要注意的集合不变性问题,并提供了具体的代码实现。通过示例代码展示了如何避免直接修改原始集合,以及测试用例来验证这些操作的正确性。

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

前言

前几天. 工作中用到了List的交集, 并集, 补集. 运算. 之前有封装过相关的List工具类. 在此, 再次总结一下.


List 的交集/并集/补集 运算(原生方法)

  • 交集
    /**
     * 交集.
     * 注意直接使用 retainAll方法会改变原数据集合. 需要拷贝使用.
     */
    public static <T> List<T> intersection(java.util.List<T> listA, List<T> listB){
        if(CollectionUtils.isEmpty(listA)){
            return listB;
        } else if(CollectionUtils.isEmpty(listB)){
            return listA;
        }

        List<T> copyOfArrayListA = new ArrayList<>(listA);
        copyOfArrayListA.retainAll(listB);
        return copyOfArrayListA;
    }
  • 并集
    /**
     * 并集.
     */
    public static <T> List<T> union(java.util.List<T> listA, List<T> listB){
        if(CollectionUtils.isEmpty(listA)){
            return listB;
        } else if(CollectionUtils.isEmpty(listB)){
            return listA;
        }

        List<T> copyOfArrayListA = new ArrayList<>(listA);
        copyOfArrayListA.removeAll(listB);
        copyOfArrayListA.addAll(listB);
        return copyOfArrayListA;
    }
  • 补集
    /**
     * 补集.
     */
    public static <T> List<T> complement(java.util.List<T> listA, List<T> listB){
        if(CollectionUtils.isEmpty(listA)){
            return listB;
        } else if(CollectionUtils.isEmpty(listB)){
            return listA;
        }

        List<T> intersectionCollection = intersection(listA, listB);
        List<T> unionCollection = union(listA, listB);

        unionCollection.removeAll(intersectionCollection);

        return unionCollection;
    }
  • 测试
    public static <T> void testPrintListData(List<T> dataList){
        if(CollectionUtils.isEmpty(dataList)){
            return;
        }
        System.out.println("DataList Print:");
        System.out.print("[");
        dataList.forEach(data ->{
            System.out.print(data.toString()+" ");
        });
        System.out.print("]");
        System.out.println("");
    }

    public static void main(String[] args) {
        List<String> listA = new ArrayList<>();
        listA.add("A");
        listA.add("C");
        listA.add("D");
        List<String> listB = new ArrayList<>();
        listB.add("A");
        listB.add("B");
        listB.add("C");

        List<String> intersectionList = intersection(listA, listB);
        System.out.println("Intersection:");
        testPrintListData(intersectionList);

        List<String> unionList = union(listA, listB);
        System.out.println("Union:");
        testPrintListData(unionList);

        List<String>  complement = complement(listA, listB);
        System.out.println("Complement:");
        testPrintListData(complement);
    }
  • 测试结果
Intersection:
DataList Print:
[A C ]
Union:
DataList Print:
[D A B C ]
Complement:
DataList Print:
[D B ]

  • 要点1 如何判断2个对象相同?

    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }
    /**
     * Returns <tt>true</tt> if this list contains the specified element.
     * More formally, returns <tt>true</tt> if and only if this list contains
     * at least one element <tt>e</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
     *
     * @param o element whose presence in this list is to be tested
     * @return <tt>true</tt> if this list contains the specified element
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

基于以上方法. 我们可以看出. 此方法主要是使用, equals()方法来进行实现的.

  • 要点2

直接使用retainAll()等方法. 会直接改变原集合的值. 在使用中需要使用拷贝集合进行操作.


Collections工具包内

TODO.


Reference

[1]. java list 交集 并集 差集 去重复并集

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值