如何用两个键(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
另一种方法。
数组索引, 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;
有几个选项:
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; } }
您可以将维度指标X
和Y
设为公共访问级别,因为它们是最终的,并且不包含敏感信息。 在将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;
在common-collections [MultiKeyMap]中实现( https://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/map/MultiKeyMap.html )
创build一个代表复合键的值类,例如:
class Index2D { int first, second; // overrides equals and hashCode properly here }
注意正确地重写equals()
和hashCode()
。 如果这看起来像很多工作,你可能会考虑一些现成的通用容器,比如Apache公用程序提供的Pair
。
这里也有很多类似的问题 ,其他的想法,比如使用Guava的Table ,虽然允许键具有不同的types,但是在你的情况下,这可能是过度的(内存使用和复杂性),因为我知道你的键都是整数。
如果他们是两个整数,你可以尝试一个快速和肮脏的把戏: Map<String, ?>
使用的密钥作为i+"#"+j
。
如果密钥i+"#"+j
与j+"#"+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");