我有一个整数的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;
有几种选择:
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));
Table
Table<Integer, Integer, V> table = HashBasedTable.create();
//...
table.get(2, 5);
Table
使用下面的地图。
请注意,特殊的Key
类是唯一可以扩展到n维的方法。您可能还会考虑:
Map<List<Integer>, V> map = //...
但从性能角度来看,这是可怕的,以及可读性和正确性(没有简单的方法来强制列表大小)。
也许看看Scala你有元组和case
类(用单线代替整个Key
类)。
使用Pair
作为HashMap
的关键。 JDK没有配对,但你可以使用http://commons.apache.org/lang这样的第三方图书馆,也可以自己编写一对配对。
您也可以使用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");
当您创建自己的密钥对对象时,您应该面对一些事情。
首先,你应该知道实施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
访问级别是否在任何情况下都能正常工作。
如果你对决赛感到好奇,我会宣布任何事情都是最终的,在实例化时设置的值并且永远不会改变 - 因此它是一个对象常量。
您不能拥有包含多个键的哈希映射,但您可以拥有一个以多个参数作为键的对象。
创建一个名为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>
得到你的结果。 :)
在共同收藏品MultiKeyMap中实施
两种可能性。使用组合键:
class MyKey {
int firstIndex;
int secondIndex;
// important: override hashCode() and equals()
}
或地图:
Map<Integer, Map<Integer, Integer>> myMap;
如果它们是两个整数,你可以尝试一个快速而肮脏的技巧:Map<String, ?>
使用密钥作为i+"#"+j
。
如果关键i+"#"+j
与j+"#"+i
相同,请尝试min(i,j)+"#"+max(i,j)
。
创建一个代表复合键的值类,例如:
class Index2D {
int first, second;
// overrides equals and hashCode properly here
}
注意正确地覆盖equals()
和hashCode()
。如果这看起来很多工作,你可能会考虑一些现成的通用容器,比如apache commons等提供的Pair
。
这里也有很多similar questions,还有其他的想法,比如使用Guava的Table,虽然允许键有不同的类型,在你的情况下可能是过度的(在内存使用和复杂性),因为我知道你的键都是整数。
你可以像这样创建你的密钥对象:
公共类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应该是不可变的。只有这样,您才能构建稳定的密钥对象。
我们可以创建一个类来传递多个键或值,并且该类的对象可以用作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();
}
}
}
}