我有一个整数的2D数组。我希望将它们放入HashMap中。但我想基于Array Index访问HashMap中的元素。类似的东西:
对于A [2] [5],map.get(2,5)
返回与该键相关联的值。但是如何使用一对键创建hashMap?或者一般来说,多个键:Map<((key1, key2,..,keyN), Value)
以我可以使用get(key1,key2,... keyN)访问元素的方式。
编辑:发布问题3年后,我想再增加一点
我遇到NxN matrix
的另一种方式。
数组索引,i
和j
可以通过以下方式表示为单个key
:
int key = i * N + j;
//map.put(key, a[i][j]); // queue.add(key);
可以通过这种方式从key
撤销指数:
int i = key / N;
int j = key % N;
答案 0 :(得分:178)
有几种选择:
Map<Integer, Map<Integer, V>> map = //...
//...
map.get(2).get(5);
public class Key {
private final int x;
private final int y;
public Key(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Key)) return false;
Key key = (Key) o;
return x == key.x && y == key.y;
}
@Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
在此实施equals()
和hashCode()
至关重要。然后你只需使用:
Map<Key, V> map = //...
和
map.get(new Key(2, 5));
来自Guava的Table
Table<Integer, Integer, V> table = HashBasedTable.create();
//...
table.get(2, 5);
Table
使用下面的地图地图。
请注意,特殊Key
类是唯一可扩展到n维的方法。您可能还会考虑:
Map<List<Integer>, V> map = //...
但从性能角度来看,这是可怕的,以及可读性和正确性(没有简单的方法来强制列表大小)。
也许看看Scala,你有哪些元组和case
类(用一行代替整个Key
类)。
答案 1 :(得分:19)
当你创建自己的密钥对对象时,你应该面对一些事情。
首先,您应该了解实施hashCode()
和equals()
。你需要这样做。
其次,在实施hashCode()
时,请确保了解其工作原理。给定的用户示例
public int hashCode() {
return this.x ^ this.y;
}
实际上是你可以做的最糟糕的实现之一。原因很简单:你有很多平等的哈希!并且hashCode()
应该返回往往很少见的int值,这是唯一最好的值。使用这样的东西:
public int hashCode() {
return (X << 16) + Y;
}
这很快并且为-2 ^ 16和2 ^ 16-1(-65536到65535)之间的键返回唯一的哈希值。几乎适用于任何情况。很少有人超出这个范围。
第三,实施equals()
时也知道它的用途,并了解如何创建密钥,因为它们是对象。通常你会做不必要的if语句,因为你总是会得到相同的结果。
如果您创建这样的键:map.put(new Key(x,y),V);
,您永远不会比较键的引用。因为每次你想访问地图,你都会做map.get(new Key(x,y));
之类的事情。因此,equals()
不需要if (this == obj)
之类的语句。 永远不会发生。
而不是if (getClass() != obj.getClass())
equals()
更好地使用if (!(obj instanceof this))
。它甚至对子类也有效。
所以你唯一需要比较的就是X和Y.所以在这种情况下最好的equals()
实现是:
public boolean equals (final Object O) {
if (!(O instanceof Key)) return false;
if (((Key) O).X != X) return false;
if (((Key) O).Y != Y) return false;
return true;
}
所以最后你的关键类是这样的:
public class Key {
public final int X;
public final int Y;
public Key(final int X, final int Y) {
this.X = X;
this.Y = Y;
}
public boolean equals (final Object O) {
if (!(O instanceof Key)) return false;
if (((Key) O).X != X) return false;
if (((Key) O).Y != Y) return false;
return true;
}
public int hashCode() {
return (X << 16) + Y;
}
}
您可以为维度索引X
和Y
提供公共访问级别,因为它们是最终的,并且不包含敏感信息。在将private
转换为Object
时,我不能100%确定Key
访问级别是否在任何情况下正常运行。
如果你对决赛感到好奇,我会宣布任何事情都是最终的,在实例化时设置值并且永远不会改变 - 因此是一个对象常量。
答案 2 :(得分:6)
您不能拥有包含多个键的哈希映射,但您可以拥有一个以多个参数为键的对象。
创建一个名为Index的对象,该对象采用x和y值。
public class Index {
private int x;
private int y;
public Index(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
return this.x ^ this.y;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Index other = (Index) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
然后让您的HashMap<Index, Value>
获得结果。 :)
答案 3 :(得分:3)
两种可能性。使用组合密钥:
class MyKey {
int firstIndex;
int secondIndex;
// important: override hashCode() and equals()
}
或地图:
Map<Integer, Map<Integer, Integer>> myMap;
答案 4 :(得分:3)
在common-collections [MultiKeyMap]中实现 (https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/MultiKeyMap.html)
答案 5 :(得分:2)
如果它们是两个整数,你可以尝试快速而肮脏的技巧:Map<String, ?>
使用密钥i+"#"+j
。
如果密钥i+"#"+j
与j+"#"+i
相同,请尝试min(i,j)+"#"+max(i,j)
。
答案 6 :(得分:1)
创建一个代表复合键的值类,例如:
class Index2D {
int first, second;
// overrides equals and hashCode properly here
}
注意正确覆盖equals()
和hashCode()
。如果这看起来很多,你可以考虑一些现成的通用容器,比如apache commons等提供的Pair
。
这里还有很多similar questions和其他想法,例如使用Guava的Table,虽然允许键具有不同的类型,这可能是过度的(在内存使用和复杂性方面)因为我明白你的密钥都是整数。
答案 7 :(得分:1)
你可以创建这样的关键对象:
公共类MapKey {
public Object key1;
public Object key2;
public Object getKey1() {
return key1;
}
public void setKey1(Object key1) {
this.key1 = key1;
}
public Object getKey2() {
return key2;
}
public void setKey2(Object key2) {
this.key2 = key2;
}
public boolean equals(Object keyObject){
if(keyObject==null)
return false;
if (keyObject.getClass()!= MapKey.class)
return false;
MapKey key = (MapKey)keyObject;
if(key.key1!=null && this.key1==null)
return false;
if(key.key2 !=null && this.key2==null)
return false;
if(this.key1==null && key.key1 !=null)
return false;
if(this.key2==null && key.key2 !=null)
return false;
if(this.key1==null && key.key1==null && this.key2 !=null && key.key2 !=null)
return this.key2.equals(key.key2);
if(this.key2==null && key.key2==null && this.key1 !=null && key.key1 !=null)
return this.key1.equals(key.key1);
return (this.key1.equals(key.key1) && this.key2.equals(key2));
}
public int hashCode(){
int key1HashCode=key1.hashCode();
int key2HashCode=key2.hashCode();
return key1HashCode >> 3 + key2HashCode << 5;
}
}
这样做的好处是:它总能确保您覆盖所有场景的Equals。
注意:您的key1和key2应该是不可变的。只有这样,你才能构建一个稳定的密钥对象。
答案 8 :(得分:1)
我们可以创建一个类来传递多个键或值,并且该类的对象可以用作map中的参数。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
public class key1 {
String b;
String a;
key1(String a,String b)
{
this.a=a;
this.b=b;
}
}
public class read2 {
private static final String FILENAME = "E:/studies/JAVA/ReadFile_Project/nn.txt";
public static void main(String[] args) {
BufferedReader br = null;
FileReader fr = null;
Map<key1,String> map=new HashMap<key1,String>();
try {
fr = new FileReader(FILENAME);
br = new BufferedReader(fr);
String sCurrentLine;
br = new BufferedReader(new FileReader(FILENAME));
while ((sCurrentLine = br.readLine()) != null) {
String[] s1 = sCurrentLine.split(",");
key1 k1 = new key1(s1[0],s1[2]);
map.put(k1,s1[2]);
}
for(Map.Entry<key1,String> m:map.entrySet()){
key1 key = m.getKey();
String s3 = m.getValue();
System.out.println(key.a+","+key.b+" : "+s3);
}
// }
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
if (fr != null)
fr.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
答案 9 :(得分:0)
使用Pair
作为HashMap
的密钥。 JDK没有配对,但您可以使用第三方图书馆,例如http://commons.apache.org/lang,也可以写一对你自己的配对。
答案 10 :(得分:0)
您也可以使用 guava Table 实现。
表表示一个特殊的映射,其中可以以组合方式指定两个键以引用单个值。它类似于创建地图地图。
//create a table
Table<String, String, String> employeeTable = HashBasedTable.create();
//initialize the table with employee details
employeeTable.put("IBM", "101","Mahesh");
employeeTable.put("IBM", "102","Ramesh");
employeeTable.put("IBM", "103","Suresh");
employeeTable.put("Microsoft", "111","Sohan");
employeeTable.put("Microsoft", "112","Mohan");
employeeTable.put("Microsoft", "113","Rohan");
employeeTable.put("TCS", "121","Ram");
employeeTable.put("TCS", "122","Shyam");
employeeTable.put("TCS", "123","Sunil");
//get Map corresponding to IBM
Map<String,String> ibmEmployees = employeeTable.row("IBM");
答案 11 :(得分:0)
您可以从以下链接下载它: https://github.com/VVS279/DoubleKeyHashMap/blob/master/src/com/virtualMark/doubleKeyHashMap/DoubleKeyHashMap.java
https://github.com/VVS279/DoubleKeyHashMap
您可以使用双键:值哈希图,
DoubleKeyHashMap<Integer, Integer, String> doubleKeyHashMap1 = new
DoubleKeyHashMap<Integer, Integer, String>();
DoubleKeyHashMap<String, String, String> doubleKeyHashMap2 = new
DoubleKeyHashMap<String, String, String>();
答案 12 :(得分:0)
Java 7+ 包含一个新的 Map.Entry<K,V>
类,您可以将其用作地图的键(或集合的条目)。它还包含一个 Map.entry(K k, V v)
以轻松创建新的 Map.Entry
对象。
用法:
Map<Map.Entry<Integer,Integer>, Integer> map = new HashMap<>();
map.put(Map.entry(1, 2), 0);