使用哈希码比较 Map 的关键元素
Comparing key elements of a Map using their hash codes
我想使用 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)。
我的假设正确吗?我可以使用哈希码来比较密钥吗?
您不需要明确地这样做。
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]
如果我需要对键进行排序怎么办(这里,按它们的自然顺序)?
两种解决方案。
改用 TreeMap
Map<Integer,String> map = new TreeMap<Integer, String>();
稍后将 Set
包裹在 TreeSet
周围
System.out.println(new TreeSet<Integer>(map.keySet()));
你的假设不正确。
来自 Wikipedia:
In the Java programming language, every class implicitly or explicitly
provides a hashCode() method, which digests the data stored in an
instance of the class into a single hash value (a 32-bit signed
integer). This hash is used by other code when storing or
manipulating the instance (...). This property is important to the
performance of hash tables and other data structures that store
objects in groups ("buckets") based on their computed hash values.
现在,您的每个实例都有一个哈希码,可以与其他对象的哈希码相同或不同。 Map
集合使用密钥的哈希码(通过 hashcode()
方法)在内部将数据存储在存储桶中(如果您想了解更多详细信息,请查看 here)。
如前所述,这并不意味着存储在同一个桶中的所有对象肯定具有相同或不同的哈希码。
更新:为什么要使用哈希码比较对象?如果你想比较映射的键或值,我建议你通过迭代它们的集合来进行值或对象比较(你可以分别通过 map.keySet()
或 map.values()
得到它们)和不是 通过使用哈希码。您无法确定 hashCode() 的值对于不同的对象是相同的还是不同的。
有多种方法可以实现这一点,即单键 -> 多值
- 使用Hashmap和arraylist结合
- 使用 guava collections 的 multimap
- 使用 apache commons collection 提供的 multimap
详细解释如下:
http://java.dzone.com/articles/hashmap-%E2%80%93-single-key-and
在我看来,你真正想要的是让名字成为地图的关键,相应的telephone号码设置价值。
您还希望您的密钥不区分大小写...大小写不同的字符串实例将具有不同的哈希码,因此您不能在此处将它们用作密钥本身。然后你需要做的是在访问地图时将名称转换为规范形式,比如全部小写,这样大小写差异就不再相关了。
有几种方法可以解决此问题...扩展 HashMap 以满足您的需求是一种优雅的方法。
最好使用字符串来存储 phone 数字,因为它们通常包含非数字字符...
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 映射中的一些其他操作以确保保持一致性。
我想使用 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)。
我的假设正确吗?我可以使用哈希码来比较密钥吗?
您不需要明确地这样做。
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]
如果我需要对键进行排序怎么办(这里,按它们的自然顺序)?
两种解决方案。
改用
TreeMap
Map<Integer,String> map = new TreeMap<Integer, String>();
稍后将
Set
包裹在TreeSet
周围System.out.println(new TreeSet<Integer>(map.keySet()));
你的假设不正确。
来自 Wikipedia:
In the Java programming language, every class implicitly or explicitly provides a hashCode() method, which digests the data stored in an instance of the class into a single hash value (a 32-bit signed integer). This hash is used by other code when storing or manipulating the instance (...). This property is important to the performance of hash tables and other data structures that store objects in groups ("buckets") based on their computed hash values.
现在,您的每个实例都有一个哈希码,可以与其他对象的哈希码相同或不同。 Map
集合使用密钥的哈希码(通过 hashcode()
方法)在内部将数据存储在存储桶中(如果您想了解更多详细信息,请查看 here)。
如前所述,这并不意味着存储在同一个桶中的所有对象肯定具有相同或不同的哈希码。
更新:为什么要使用哈希码比较对象?如果你想比较映射的键或值,我建议你通过迭代它们的集合来进行值或对象比较(你可以分别通过 map.keySet()
或 map.values()
得到它们)和不是 通过使用哈希码。您无法确定 hashCode() 的值对于不同的对象是相同的还是不同的。
有多种方法可以实现这一点,即单键 -> 多值
- 使用Hashmap和arraylist结合
- 使用 guava collections 的 multimap
- 使用 apache commons collection 提供的 multimap
详细解释如下: http://java.dzone.com/articles/hashmap-%E2%80%93-single-key-and
在我看来,你真正想要的是让名字成为地图的关键,相应的telephone号码设置价值。
您还希望您的密钥不区分大小写...大小写不同的字符串实例将具有不同的哈希码,因此您不能在此处将它们用作密钥本身。然后你需要做的是在访问地图时将名称转换为规范形式,比如全部小写,这样大小写差异就不再相关了。
有几种方法可以解决此问题...扩展 HashMap 以满足您的需求是一种优雅的方法。
最好使用字符串来存储 phone 数字,因为它们通常包含非数字字符...
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 映射中的一些其他操作以确保保持一致性。