关于java:List-去重的-6-种方法这个方法最完美

39次阅读

共计 4503 个字符,预计需要花费 12 分钟才能阅读完成。

在日常的业务开发中,偶然会遇到须要将 List 汇合中的反复数据去除掉的场景。这个时候可能有同学会问:为什么不间接应用 Set 或者 LinkedHashSet 呢?这样不就没有反复数据的问题了嘛?

不得不说,能提这个问题的同学很机智,一眼就看到了问题的实质。

然而,在理论的业务开发中遇到的状况会更简单。比方,List 汇合可能是历史遗留问题,也有可能是调用接口返回的类型限度,只能应用 List 接管,又或者是代码写了一半,在做多个汇合合并的时候才发现了这个问题,总之造成问题的起因有很多种,这里就不一一列举了。

当发现这个问题之后,如果能够通过革新原有代码,把原来的 List 类型替换成 Set 类型,那就能够间接批改汇合的类型即可。但如果压根就批改不了,或者是批改的老本太大,那接下来这 6 种去重的办法,将帮你解决问题。

前置常识

正式开始之前,先来搞懂两组概念: 无序汇合和有序汇合 & 无序和有序 。因为接下来的办法实现中,会重复提及这两组概念,所以有必要在正式开始之前,先把它们搞清楚。

无序汇合

无序汇合是指,数据读取的程序和数据插入的程序是不统一的。例如,插入汇合的程序是:1、5、3、7,而汇合的读取程序居然是:1、3、5、7。

有序汇合

有序汇合的概念和无序汇合的概念正好相同,它是指汇合的读取程序和插入程序是统一的。例如,插入数据的程序是:1、5、3、7,那么读取的程序也是:1、5、3、7。

有序和无序

通过下面的无序汇合和有序汇合,咱们能够得出有序和无序的概念。
有序指的是数据的排列程序和读取程序合乎咱们的预期就叫做有序。而无序指的是数据的排列程序和读取程序不合乎咱们的预期就叫做无序。

PS:如果对于有序和无序的概念不是很分明也没关系,通过上面的事例,咱们能够进一步的了解它们的含意。

办法 1:contains 判断去重 (有序)

要进行数据去重,咱们首先想到的是新建一个汇合,而后循环原来的汇合,每次循环判断原汇合中的循环项,如果以后循环的数据,没有在新汇合中存在就插入,曾经存在了就舍弃,这样当循环执行完,咱们就失去了一个没有反复元素的汇合了,实现代码如下:

public class ListDistinctExample {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>() {{add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原汇合:" + list);
        method(list);
    }

    /**
     * 自定义去重
     * @param list
     */
    public static void method(List<Integer> list) {
        // 新汇合
        List<Integer> newList = new ArrayList<>(list.size());
        list.forEach(i -> {if (!newList.contains(i)) { // 如果新汇合中不存在则插入
                newList.add(i);
            }
        });
        System.out.println("去重汇合:" + newList);
    }
}

以上程序执行的后果,如下所示:

此办法的长处是:了解起来比较简单,并且最终失去的汇合也是有序的,这里的有序指的是新汇合的排列程序和原汇合的程序是统一的;但毛病是实现代码有点多,不够简洁优雅。

办法 2:迭代器去重 (无序)

自定义 List 去重,除了下面的新建汇合之外,咱们也能够应用迭代器循环判断每一项数据,如果以后循环的数据,在汇合中存在两份或两份以上,就将以后的元素删除掉,这样循环完之后,也能够失去一个没有反复数据的汇合,实现代码如下:

public class ListDistinctExample {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>() {{add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原汇合:" + list);
        method_1(list);
    }

    /**
     * 应用迭代器去重
     * @param list
     */
    public static void method_1(List<Integer> list) {Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            // 获取循环的值
            Integer item = iterator.next();
            // 如果存在两个雷同的值
            if (list.indexOf(item) != list.lastIndexOf(item)) {
                // 移除最初那个雷同的值
                iterator.remove();}
        }
        System.out.println("去重汇合:" + list);
    }
}

以上程序执行的后果,如下所示:

此办法的实现比上一种办法的实现代码要少一些,并且不须要新建汇合,但此办法失去的新汇合是无序的,也就是新汇合的排列程序和原汇合不统一,因而也不是最优的解决方案。

办法 3:HashSet 去重 (无序)

咱们晓得 HashSet 天生具备“去重”的个性,那咱们只须要将 List 汇合转换成 HashSet 汇合就能够了,实现代码如下:

public class ListDistinctExample {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>() {{add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原汇合:" + list);
        method_2(list);
    }

    /**
     * 应用 HashSet 去重
     * @param list
     */
    public static void method_2(List<Integer> list) {HashSet<Integer> set = new HashSet<>(list);
        System.out.println("去重汇合:" + set);
    }
}

以上程序执行的后果,如下所示:

此办法的实现代码较为简洁,但毛病是 HashSet 会主动排序,这样新汇合的数据排序就和原汇合不统一了,如果对汇合的程序有要求,那么此办法也不能满足以后需要。

办法 4:LinkedHashSet 去重 (有序)

既然 HashSet 会主动排序不能满足需要,那就应用 LinkedHashSet,它既能去重又能保障汇合的程序,实现代码如下:

public class ListDistinctExample {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>() {{add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原汇合:" + list);
        method_3(list);
    }

    /**
     * 应用 LinkedHashSet 去重
     * @param list
     */
    public static void method_3(List<Integer> list) {LinkedHashSet<Integer> set = new LinkedHashSet<>(list);
        System.out.println("去重汇合:" + set);
    }
}

以上程序执行的后果,如下所示:

从上述代码和执行后果能够看出,LinkedHashSet 是到目前为止,实现比较简单,且最终生成的新汇合与原汇合程序保持一致的实现办法,是咱们能够思考应用的一种去重办法。

办法 5:TreeSet 去重 (无序)

除了以上的 Set 汇合之外,咱们还能够应用 TreeSet 汇合来实现去重性能,实现代码如下:

public class ListDistinctExample {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>() {{add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原汇合:" + list);
        method_4(list);
    }

    /**
     * 应用 TreeSet 去重 (无序)
     * @param list
     */
    public static void method_4(List<Integer> list) {TreeSet<Integer> set = new TreeSet<>(list);
        System.out.println("去重汇合:" + set);
    }
}

以上程序执行的后果,如下所示:

比拟遗憾的是,TreeSet 尽管实现起来也比较简单,但它有着和 HashSet 一样的问题,会主动排序,因而也不能满足咱们的需要。

办法 6:Stream 去重 (有序)

JDK 8 为咱们带来了一个十分实用的办法 Stream,应用它能够实现很多性能,比方上面的去重性能:

public class ListDistinctExample {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>() {{add(1);
            add(3);
            add(5);
            add(2);
            add(1);
            add(3);
            add(7);
            add(2);
        }};
        System.out.println("原汇合:" + list);
        method_5(list);
    }

    /**
     * 应用 Stream 去重
     * @param list
     */
    public static void method_5(List<Integer> list) {list = list.stream().distinct().collect(Collectors.toList());
        System.out.println("去重汇合:" + list);
    }
}

以上程序执行的后果,如下所示:

Stream 实现去重性能和其余办法不同的是,它不必新创建汇合,应用本身接管一个去重的后果就能够了,并且实现代码也很简洁,并且去重后的汇合程序也和原汇合的程序保持一致,是咱们最优先思考的去重办法。

总结

本文咱们介绍了 6 种汇合去重的办法,其中实现最简洁,且去重之后的程序能和原汇合保持一致的实现办法,只有两种:LinkedHashSet 去重和 Stream 去重,而后一种去重办法无需借助新汇合,是咱们优先思考的去重办法。

是非审之于己,毁誉听之于人,得失安之于数。

博主介绍:80 后程序员,写博客这件事“保持”了 11 年,喜好:读书、慢跑、羽毛球。

我的公众号:Java 面试真题解析

集体微信:GG_Stone,欢送围观朋友圈,做个点赞只交。

正文完
 0