面試官:怎麼刪除 HashMap 中的重複元素?第 3 種實現思路,99% 的人不會!

張哥說技術發表於2023-03-14



背景

大家好,我是棧長。

前些天,棧長給大家分享了 3 篇實用的文章:

  • 帶了一個 3 年的開發,不會迴圈刪除 List 中的元素,我簡直崩潰!!
  • 面試官:怎麼去除 List 中的重複元素?我一行程式碼搞定,趕緊拿去用!
  • 面試官:怎麼刪除 HashMap 中的元素?我一行程式碼搞定,趕緊拿去用!

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", "王五");
}};

本文所有完整示例原始碼已經上傳:

歡迎 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 進行去重了,輸出結果:

{李四=user2, 張三=user1, 王五=user8, 趙六=user6}

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

第二次收集:

現在的 Key 是之前的 Value,所以需要再相互換過來,輸出結果:

{user1=張三, user2=李四, user8=王五, user6=趙六}

這個方法比較繞,雖然能一行程式碼搞定,但程式碼很冗餘,不是很優雅,最重要的是這兩次的收集過程會建立兩次新 Map,相對比較耗記憶體。

總結

本文總結了 3 種刪除 HashMap 重複元素的方法:

  • 新建立 Map 新增不重複元素
  • 新增 Set 再刪除重複元素(推薦)
  • 使用 Stream 刪除重複元素

實際開發過程中,可能會使用不同的遍歷方式,使用哪種刪除方案可以根據不同的遍歷方式進行選擇,但推薦使用 Set 方案,可以直接刪除 Map 中的重複元素,不會建立新的 HashMap。

另外,遍歷集合時需要重點考慮是否有多執行緒修改元素的場景,可能導致的併發修改異常,參考之前文章中介紹的方案,這裡不再撰述了。

本文所有完整示例原始碼已經上傳:

歡迎 Star 學習,後面 Java 示例都會在這上面提供!

你身邊還有誰不會刪除 HashMap 中的重複元素?把這篇文章發給他吧,讓大家少走彎路,少寫垃圾程式碼,共同進步。

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

好了,今天的分享就到這裡了,後面棧長會分享更多好玩的 Java 技術和最新的技術資訊,關注公眾號Java技術棧第一時間推送,我也將主流 Java 面試題和參考答案都整理好了,大家可以在Java面試庫小程式進行刷題。

版權宣告: 本文系公眾號 "Java技術棧" 原創,轉載、引用本文內容請註明出處,抄襲、洗稿一律投訴侵權,後果自負,並保留追究其法律責任的權利。

End


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024923/viewspace-2939563/,如需轉載,請註明出處,否則將追究法律責任。

相關文章