Java 找出Arraylist 中的重复元素

List 是 Java 中十分常见的数据结构,它与 Set 不同的一点是,可以存放相同的数据。有时候,我们想知道 Arraylist 中有哪些重复数据,这里提供几个思路。

数据分析

下面给出了一个包含重复数据的 list:

List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "E", "D", "E");

现在我们需要得到的数据为:

  • E 重复 3 次
  • D 重复 2 次

承接这样的数据,我们首先想到的就是 Map,它能够很方便地记录某个元素重复出现多少次。

实现方案

下面,我们将研究一些不同的方法来计算ArrayList中的重复元素,返回一个 Map。

循环计数

我们的预期结果是一个Map对象,它包含输入列表中的所有元素作为键,每个元素的计数作为值。

最直接的解决方案是遍历输入列表和每个元素:

  • 如果resultMap包含该元素,我们将计数器加 1
  • 否则,构建一个新的键值对
private static void duplList(List<String> list){
    Map<String, Integer> map = new HashMap<>();
    for(String str : list){
        if(map.containsKey(str)){
            map.put(str, map.get(str) + 1);
        } else{
            map.put(str, 1);
        }
    }
    System.out.println(map);
}

当然,我们可以利用一些 Java8 中的特性来简化一下写法:

private static void duplList(List<String> list){
    Map<String, Integer> map = new HashMap<>();
    list.forEach(s -> map.put(s, map.getOrDefault(s, 0) + 1));
    System.out.println(map);
}
{A=1, B=1, C=1, D=2, E=3, F=1}

Map 的 compute()

Map 中新加入的 compute() 方法,可以方便地操作 Map,其第二个参数是一个 BiFunction 接口。对于给定的键,它要么返回1,要么返回其当前值加 1.

private static void dupListCompute(List<String> list){
    Map<String, Integer> map = new HashMap<>();
    list.forEach(s -> map.compute(s, (k, v) -> v == null ? 1 : v + 1));
}

Map 的 merge()

使用 merge() 方法有个好处——不用处理空值。

private static void dupListMerge(List<String> list){
    Map<String, Integer> map = new HashMap<>();
    list.forEach(s -> map.merge(s, 1, Integer::sum));
}

Collectors.toMap()

Stream API 中也提供了非常多实用的方法:

private static void dupListToMap(List<String> list){
    Map<String, Integer> map = list.stream()
        .collect(Collectors.toMap(Function.identity(), v -> 1, Integer::sum));
}

方法被极致压缩到只有一行代码。

Collectors.groupingBy()

利用 Collectors.groupingBy()和Collectors.counting() 更近一步减少代码。

这是代码量最少的解决方案,也是最不容易看懂代码逻辑的方案。

private static void dupListGroupingBy(List<String> list){
    Map<String, Long> collect = list.stream()
        .collect(Collectors.groupingBy(s -> s, Collectors.counting()));
}

泛化

上面的例子中,我们默认的 List 中为 String ,实际上,该数据可以是任意类型。由于需要作为 Map 的key,该对象应该满足一定条件

为了泛化方法,适配各种不同类型的List,我们的方法签名可以改写如下:

public <T> Map<T, Long> dupList(List<T> inputList) {
    return inputList.stream().collect(Collectors.groupingBy(k -> k, Collectors.counting()));
}

方法内部并没有用到 String 的特殊方法,因此,上述例子中方法体不用做任何修改即可适配所有场景。

转载请注明出处:码谱记录 » Java 找出Arraylist 中的重复元素
标签: