如何用两个键(Key-Pair,Value)创build一个HashMap?

我有一个整数的二维数组。 我希望他们被放入一个HashMap。 但我想从基于数组索引的HashMap中访问元素。 就像是:

对于A [2] [5], map.get(2,5)返回与该键相关的值。 但是,我怎么用一对钥匙创build一个哈希映射? 或者一般来说,我可以通过使用get(key1,key2,… keyN)来访问元素的方式: Map<((key1, key2,..,keyN), Value) )。

编辑:发布这个问题3年后,我想添加更多一点

我碰到了NxN matrix另一种方法。

数组索引, ij可以用下面的方式表示为一个单独的key

 int key = i * N + j; //map.put(key, a[i][j]); // queue.add(key); 

而且指数可以通过这种方式从key中撤回:

 int i = key / N; int j = key % N; 

有几个选项:

2个维度

地图的地图

 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使用下面的地图的地图

N维度

请注意,特殊的Key类是缩放到n维的唯一方法。 你也可以考虑:

 Map<List<Integer>, V> map = //... 

但是从性能的angular度来看,这是非常糟糕的,以及可读性和正确性(没有简单的方法来执行列表大小)。

也许看看你有元组和类的Scala(用一行代替整个Key类)。

当你创build自己的密钥对对象时,你应该面对一些事情。

首先,你应该知道实现hashCode()equals() 。 你将需要这样做。

其次,在实现hashCode() ,确保你了解它是如何工作的。 给定的用户示例

 public int hashCode() { return this.x ^ this.y; } 

实际上是你能做的最糟糕的实现之一。 原因很简单:你有很多相同的哈希值! 并且hashCode()应该返回int值,这些值通常是很less见的,最好是唯一的。 使用这样的东西:

 public int hashCode() { return (X << 16) + Y; } 

这是快速的,并返回-2 ^ 16和2 ^ 16-1(-65536到65535)之间的密钥的唯一哈希值。 几乎适用于任何情况。 你很less走出这个界限。

第三,在实现equals()也知道它的用途,并且知道你是如何创build你的密钥的,因为它们是对象。 通常你做不必要的陈述,因为你总会有相同的结果。

如果你创build这样的键: 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; } } 

您可以将维度指标XY设为公共访问级别,因为它们是最终的,并且不包含敏感信息。 在将Object强制转换为Key情况下,我不能100%确定private访问级别是否正常工作。

如果你想知道决赛,我会宣布任何事情都是最终的,这个价值决定于实例而不会改变 – 因此是一个对象常量。

你不能有一个有多个键的散列图,但是你可以有一个把多个参数作为键的对象。

创build一个名为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>来得到你的结果。 🙂

两种可能性。 要么使用组合键:

 class MyKey { int firstIndex; int secondIndex; // important: override hashCode() and equals() } 

或地图的地图:

 Map<Integer, Map<Integer, Integer>> myMap; 

创build一个代表复合键的值类,例如:

 class Index2D { int first, second; // overrides equals and hashCode properly here } 

注意正确地重写equals()hashCode() 。 如果这看起来像很多工作,你可能会考虑一些现成的通用容器,比如Apache公用程序提供的Pair

这里也有很多类似的问题 ,其他的想法,比如使用Guava的Table ,虽然允许键具有不同的types,但是在你的情况下,这可能是过度的(内存使用和复杂性),因为我知道你的键都是整数。

如果他们是两个整数,你可以尝试一个快速和肮脏的把戏: Map<String, ?>使用的密钥作为i+"#"+j

如果密钥i+"#"+jj+"#"+i试试min(i,j)+"#"+max(i,j)

你可以创build你的关键对象是这样的:

公共类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应该是不可变的。 只有这样你才能够构build一个稳定的关键对象。

我们可以创build一个类来传递多个键或值,并且此类的对象可以用作地图中的参数。

 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(); } } } } 

使用Pair作为HashMap键。 JDK没有Pair,但你可以使用http://commons.apache.org/lang这样的第三方库,或者写一个你自己的Pair对。;

你也可以使用番石榴表实现这个。

表格代表一个特殊的地图,其中两个键可以组合方式指定为一个单一的值。 这与创build地图地图相似。

 //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");