【问题标题】:Comparing key elements of a Map using their hash codes [closed]使用哈希码比较地图的关键元素[关闭]
【发布时间】:2015-01-29 16:39:52
【问题描述】:

我想使用 HashCode 比较地图的元素。有可能吗?

例如,我的 HashMap 是这样的:

HashMap<Integer,String> map=new HashMap<Integer, String>();
map.put(123,"ABC");
map.put(345,"Abc");
map.put(245,"abc");

我假设所有值必须具有相同的哈希码,以便我可以比较它们并获取所有键(123,345,245)。

我的假设正确吗?我可以使用哈希码来比较密钥吗?

【问题讨论】:

  • 我不明白你的目标或假设。
  • 您的字符串值并非都具有相同的哈希码。
  • “我假设所有的值必须有相同的哈希码,这样我就可以比较它们并得到所有的键(123,345,245)。”这甚至意味着什么?

标签: java hashmap hashcode


【解决方案1】:

在我看来,您真正想要的是将名称作为地图的键,并以相应的电话号码设置值。

您还希望您的密钥不区分大小写...大小写不同的字符串实例将具有不同的哈希码,因此您不能在此处将它们用作密钥本身。然后,您需要做的是在访问地图时将名称转换为规范形式,例如全部小写,这样大小写的差异就不再相关了。

有几种方法可以解决这个问题...扩展 HashMap 以满足您的需求是一种优雅的方法。

最好使用字符串来存储电话号码,因为它们经常包含非数字字符...

public class PhoneBook extends HashMap<String,Set<String>> {

   public PhoneBook() { }

   public PhoneBook(int initialCapacity) { super(initialCapacity); }

   // Use this method to add numbers to the phone-book
   // returns true if the phone directory changed as a result of the call.
   public boolean add(String name, String number) {
        String canonicalName = name.toLowerCase();
        Set<String> existingNumbers = super.get(name);
        if (existingNumbers == null) 
            super.put(canonicalName,existingNumbers = new HashSet<>(10)); 
        // give an estimate capacity per name, in this example 10.           
        return existingNumbers.add(number);
   }  

   @Override
   public Set<String> put(String name, Set<String> numberSet) {
        throw new UnsupportedOperationException("you must use add(String) to add numbers");
   }

   @Override
   public Set<String> get(String name) {
       String canonicalName = name.toLowerCase();
       Set<String> existingNumbers = super.get(canonicalName);
       return existingNumbers == null ? Collections.EMPTY_SET : existingNumbers;
   }

} 

您可能需要覆盖 Map/Hash 映射中的一些其他操作,以确保保持一致性。

【讨论】:

  • 这很有帮助。感谢分享代码。
【解决方案2】:

您不需要明确地这样做。

HashMap 已经对其密钥进行了哈希处理。

只需调用:map.keySet() 即可获取您的密钥的Set

示例

HashMap<Integer,String> map = new HashMap<Integer, String>();
map.put(123,"ABC");
map.put(345,"Abc");
map.put(245,"abc");
System.out.println(map.keySet());

输出

[245, 123, 345]

如果我需要对键进行排序(此处,按其自然顺序)

两种解决方案。

  1. 改用TreeMap

    Map&lt;Integer,String&gt; map = new TreeMap&lt;Integer, String&gt;();

  2. 稍后将Set 包裹在TreeSet 周围

    System.out.println(new TreeSet&lt;Integer&gt;(map.keySet()));

【讨论】:

  • 感谢您的回答。我实际上想制作一个电话目录之类的东西,如果名称匹配,它应该能够检索与该名称匹配的所有电话号码。
  • @SulavaMahapatra 我建议以另一种方式映射:名称作为键,然后将一组电话号码作为值。 编辑不要不要对电话号码使用数字值!使用String。所以你会有类似Map&lt;String, Set&lt;String&gt;&gt;...
  • 是的,这将是一个正确的方法。非常感谢。
  • @SulavaMahapatra 不客气!
【解决方案3】:

有不同的方法来实现这一点,即单键 -> 多值

  1. 使用Hashmap和arraylist结合
  2. 使用番石榴集合的多图
  3. 使用 apache commons collection 提供的 multimap

下面是详细解释: http://java.dzone.com/articles/hashmap-%E2%80%93-single-key-and

【讨论】:

    【解决方案4】:

    你的假设不正确。

    来自Wikipedia

    在 Java 编程语言中,每个类都隐式或显式 提供了一个 hashCode() 方法,该方法对存储在 类的实例转换为单个哈希值(32 位有符号 整数)。其他代码在存储或存储时使用此哈希 操作实例(...)。 此属性对 哈希表和其他存储数据结构的性能 基于其计算哈希值的组(“桶”)中的对象。

    现在,您的每个实例都有一个哈希码,可以与其他对象的哈希码相同或不同。 Map 集合使用密钥的哈希码(通过 hashcode() 方法)在内部存储桶中的数据(如果您想了解更多详细信息,请查看 here)。

    如前所述,这并不意味着存储在同一个存储桶中的所有对象都肯定具有相同或不同的哈希码。

    更新:为什么要使用它们的哈希码比较对象?如果你想比较map的key或者value,我建议你通过迭代他们的集合来做一个value或者object的比较(可以分别通过map.keySet()或者map.values()得到),不要 使用哈希码。您不能确定 hashCode() 的值对于不同的对象是否相同或不同。

    【讨论】:

    • 感谢分享链接。这是否意味着我可以使用哈希码比较两个不同类的对象?
    • 我更新了答案。不必要。我建议使用哈希码以外的其他方法,因为您无法确定它们是否相同或不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2019-08-15
    • 2022-12-17
    • 2021-12-24
    • 2020-03-13
    • 2013-03-04
    相关资源
    最近更新 更多