首页 > 其他分享 >面试官:怎么删除 HashMap 中的重复元素?第 3 种实现思路,99% 的人不会!

面试官:怎么删除 HashMap 中的重复元素?第 3 种实现思路,99% 的人不会!

时间:2023-03-14 09:47:26浏览次数:54  
标签:Map 面试官 Java HashMap 删除 重复 元素 99%

背景

大家好,我是栈长。

前些天,栈长给大家分享了 3 篇实用的文章:

List 和 Map 元素的删除、去重,这些都是工作中经常遇到的问题,一些基础程序员可能会走一些弯路,所以栈长输出了三篇,希望对大家有用,其中一些编程技巧很多老程序员也没用过,所以,技术真的是学无止境。

今天栈长带来集合的删除及去重系列的最后一篇,如何删除 HashMap 中的重复元素,即怎么根据 Value 去重,去除 HashMap 中 Value 重复的元素,这也是面试官可能会问到的。

为什么不是根据 Key 去重?

大家都知道,HashMap 的 key 是不会重复的,如果有重复就会用新值覆盖旧值。

当我们向一个 HashMap 中插入元素时,HashMap 会根据这个 key 的 equals 和 hashCode 方法进行判断,如果两个 key 的值用 equals 方法比较相同,且 key 的 hashCode 值也相同,那么 HashMap 将认为这是同一个 key,后续插入相同 key 的键值对会将旧值替换为新值。

需要注意的是:

Java 中的基本数据类型和 String 等内置类,它们已经正确实现了 equals 和 hashCode 方法,可以直接用作 HashMap 的 key,而不会导致重复的 key 出现。

如果我们使用自定义类的对象作为 HashMap 的 key,需要保证这个类正确实现了 equals 和 hashCode 方法,否则可能会出现插入 "重复 key" 的情况,正常情况下,这是不符合规范和逻辑的。

HashMap 删除重复元素方案

以下 HashMap 初始测试数据:

public Map<String, String> initMap = new HashMap<>() {{
    put("user1", "张三");
    put("user2", "李四");
    put("user3", "张三");
    put("user4", "李四");
    put("user5", "王五");
    put("user6", "赵六");
    put("user7", "李四");
    put("user8", "王五");
}};

本文所有完整示例源代码已经上传:

https://github.com/javastacks/javastack

欢迎 Star 学习,后面 Java 示例都会在这上面提供!

1、新创建 Map 添加不重复元素

/**
 * 新创建 Map 添加不重复元素
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void removeDuplicated1() {
    Map<String, String> map = new HashMap<>();
    initMap.forEach((k, v) -> {
        if (!map.containsValue(v)) {
            map.put(k, v);
        }
    });
    System.out.println(map);
}

这种方法很原始,通过创建一个新 HashMap,添加元素前进行判断,如果元素在新 HashMap 中不存在才进行添加。

2、添加 Set 再删除重复元素

/**
 * 添加 Set 再删除重复元素
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void removeDuplicated2() {
    Set<String> set = new HashSet<>();
    Iterator<Map.Entry<String, String>> iterator = initMap.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, String> entry = iterator.next();
        if (!set.add(entry.getValue())) {
            iterator.remove();
        }
    }
    System.out.println(initMap);
}

这种方法和第一种方法大同小异,通过创建一个 HashSet,然后遍历 HashMap,因为 HashSet 是不允许重复元素的,所以,如果 HashSet 能添加元素说明元素没有重复,否则说明元素重复了,然后删除即可。

另外,HashSet、HashMap 的关系也是面试必问的,如果你近期准备面试跳槽,建议在Java面试库小程序在线刷题,涵盖 2000+ 道 Java 面试题,几乎覆盖了所有主流技术面试题。

3、使用 Stream 删除重复元素

/**
 * 使用 Stream 删除重复元素
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void removeDuplicated3() {
    Map<String, String> resultMap = initMap.entrySet().stream().collect(
            Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey, (key1, key2) -> key1)
    ).entrySet().stream().collect(
            Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey, (key1, key2) -> key1)
    );
    System.out.println(resultMap);
}

利用 Stream 的 collect 方法重新进行收集,这个方法也十分简单,一行代码搞定,为了可读性,文中代码进行了换行。Stream 基础就不介绍了,Stream 系列我之前写过一个专题了,不懂的关注公众号Java技术栈,然后在公众号 Java 教程菜单中阅读。

Collectors.toMap 方法返回的是一个Collector,它可以将元素累积到 Map 中,Map 的键和值将提供的映射函数应用到输入元素的结果,如果映射的键包含重复项,则值映射函数会使用提供的 merge 函数进行结果合并。

Collectors.toMap 方法可以对 Key 进行去重合并,这也是为什么进行了两次 collect 收集的原因:

第一次收集:

把 Value 作为 Key,Key 作为 Value,这样就能使用 Value 进行去重了,输出结果:

虽然能去重了,但是 HashMap 中的 Key 和 Value 值却颠倒了,所以需要第二次收集。

第二次收集:

现在的 Key 是之前的 Value,所以需要再相互换过来,输出结果:

这个方法比较绕,虽然能一行代码搞定,但代码很冗余,不是很优雅,最重要的是这两次的收集过程会创建两次新 Map,相对比较耗内存。

总结

本文总结了 3 种删除 HashMap 重复元素的方法:

  • 新创建 Map 添加不重复元素
  • 添加 Set 再删除重复元素(推荐)
  • 使用 Stream 删除重复元素

实际开发过程中,可能会使用不同的遍历方式,使用哪种删除方案可以根据不同的遍历方式进行选择,但推荐使用 Set 方案,可以直接删除 Map 中的重复元素,不会创建新的 HashMap。

另外,遍历集合时需要重点考虑是否有多线程修改元素的场景,可能导致的并发修改异常,参考之前文章中介绍的方案,这里不再撰述了。

本文所有完整示例源代码已经上传:

https://github.com/javastacks/javastack

欢迎 Star 学习,后面 Java 示例都会在这上面提供!

你身边还有谁不会删除 HashMap 中的重复元素?把这篇文章发给他吧,让大家少走弯路,少写垃圾代码,共同进步。

你还知道哪些 HashMap 去重技巧?欢迎留言分享~

好了,今天的分享就到这里了,后面栈长会分享更多好玩的 Java 技术和最新的技术资讯,关注公众号Java技术栈第一时间推送,我也将主流 Java 面试题和参考答案都整理好了,大家可以在Java面试库小程序进行刷题。

版权声明: 本文系公众号 "Java技术栈" 原创,转载、引用本文内容请注明出处,抄袭、洗稿一律投诉侵权,后果自负,并保留追究其法律责任的权利。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

标签:Map,面试官,Java,HashMap,删除,重复,元素,99%
From: https://www.cnblogs.com/javastack/p/17213765.html

相关文章

  • 99Go语言基础
    输入输出packagemainimport"fmt"funcmain(){ /** 输入和输出:fmt包 输出: fmt.Println()//打印换行 fmt.Print()//打印 fmt.Printf()//格式化打......
  • Hashtable 和 HashMap 的区别
     Hashtable:(1)Hashtable是一个散列表,它存储的内容是键值对(key-value)映射。(2)Hashtable的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。(3)Has......
  • 20230313>笔记本小升级PM991A
     新款的PM991a,有且仅有2230长度,大板子需自备转换器转成2241,2260,或者2280.  PM991a完全是小设备的福音的。以下是参数:本次产品容量512Gb, 产于2023年1月。 PM......
  • P2014 [CTSC1997] 选课
    P2014[CTSC1997]选课-洛谷|计算机科学教育新生态(luogu.com.cn)这题的技巧:把这些没有父亲节点的点,把他们的父亲节点令为0,则可从多课树变成一棵树。细节:由于0点是......
  • AcWing 199. 余数之和 题解
    做了一下午……题解都看不懂,最后自己比比划划弄懂了。题意:给出\(n,k\),求\(\sum\limits_{i=1}^nk\modi\)。首先取模形式十分不好处理,所以我们可以根据取模运算定义做......
  • HashMap的put()方法解读(Jdk1.8)
    通过本章内容来给大家解读hashMap中put()方法的逻辑流程。目录:-put()方法流程图-put()方法代码解读- 单元测试代码- put方法-......
  • 【童年回忆】4399造梦西游3,卡无限4级强化石,卡无限任务,CE修改教程
    1、无限任务卡无限任务:文本搜索otherEquip46拉下来改为otherEquip1E9,无限刷后刷新,看结果邪灵重铸:AA9020007570改204F2000F48B(改品质邪灵→传说)修改VIP5打开CE......
  • 【CF995F Cowmpany Cowmpensation】(dp+容斥)
    原题链接题意一棵\(n\)个节点的树,给每个节点分配工资(\([1,D]\)),子节点不能超过父亲节点的工资,问有多少种分配方案。$1\len\le3000$,$1\leD\le10^9$思......
  • P5752 [NOI1999] 棋盘分割题解
    本文来自我的洛谷博客。本题解力求使用清晰易懂的图片和文字,讲解最简洁的道理。请大家耐心地看完,注意要结合图片一起哦~~2022-8-24更改了格式与错别字2022-8-28更改......
  • P1996 约瑟夫问题
    P1996约瑟夫问题约瑟夫问题题目描述n个人围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,依次类推,直到所有的人都出圈,请......