Jak utworzyć Hashmapę z dwoma kluczami (para kluczy, wartość)?
Mam tablicę liczb całkowitych 2D. Chcę je umieścić w Hashmapie. Ale chcę uzyskać dostęp do elementów z HashMap na podstawie indeksu tablicy. Coś w stylu:
Dla[2][5], map.get(2,5)
który zwraca wartość powiązaną z tym kluczem. Ale jak utworzyć hashmapę za pomocą pary kluczy? Lub ogólnie, wiele kluczy: Map<((key1, key2,..,keyN), Value)
w taki sposób, że mogę uzyskać dostęp do elementu za pomocą get(key1, key2,...keyN).
EDIT: po 3 latach od zamieszczenia pytania chcę dodać trochę więcej do it
Natknąłem się na inną drogę dla NxN matrix
.
Indeksy tablicowe, i
i j
mogą być reprezentowane jako pojedyncze key
w następujący sposób:
int key = i * N + j;
//map.put(key, a[i][j]); // queue.add(key);
I indeksy można wycofać z key
w ten sposób:
int i = key / N;
int j = key % N;
11 answers
Istnieje kilka opcji:
2 Wymiary
Mapa map
Map<Integer, Map<Integer, V>> map = //...
//...
map.get(2).get(5);
Wrapper key object
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;
}
}
Implementacja equals()
i hashCode()
jest tutaj kluczowa. Następnie wystarczy użyć:
Map<Key, V> map = //...
I:
map.get(new Key(2, 5));
Table
z guawy
Table<Integer, Integer, V> table = HashBasedTable.create();
//...
table.get(2, 5);
Table
używa mapy map pod spodem.
N Wymiary
Zauważ, że Klasa specjalna Key
jest jedynym podejściem, które skaluje się do n-wymiarów. Możesz też consider:
Map<List<Integer>, V> map = //...
Ale to straszne z punktu widzenia wydajności, jak również czytelności i poprawności (nie jest łatwy sposób na wymusić rozmiar listy).
Może przyjrzyj się Scali, gdzie masz krotki i klasy case
(zastępujące całą klasę Key
klasą jednowierszową).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-11 11:37:39
Kiedy tworzysz własny obiekt pary kluczy, powinieneś zmierzyć się z kilkoma rzeczami.
Po pierwsze, powinieneś być świadomy implementacji hashCode()
i equals()
. Musisz to zrobić.
Po drugie, podczas implementacji hashCode()
Upewnij się, że rozumiesz, jak to działa. Podany przykład użytkownika
public int hashCode() {
return this.x ^ this.y;
}
Jest jedną z najgorszych implementacji, jakie możesz zrobić. Powód jest prosty: masz dużo równych hashów! A {[4] } powinien zwracać wartości int, które wydają się być rzadkie, unikalne w najlepszym razie. Użyj czegoś takiego:
public int hashCode() {
return (X << 16) + Y;
}
Jest to szybkie i zwraca unikalne skróty dla kluczy od -2^16 do 2^16-1 (od -65536 do 65535). Pasuje to prawie w każdym przypadku. Bardzo rzadko jesteś poza tą granicą.
Po trzecie, podczas implementacji equals()
również wiedzieć, do czego jest on używany i być świadomym, jak tworzysz swoje klucze, ponieważ są to obiekty. Często robisz niepotrzebne, jeśli wypowiedzi powodują, że zawsze będziesz miał ten sam wynik.
Jeśli utworzysz takie klucze: map.put(new Key(x,y),V);
nigdy nie porównaj referencje kluczy. Ponieważ za każdym razem, gdy chcesz uzyskać dostęp do mapy, zrobisz coś w stylu map.get(new Key(x,y));
. Dlatego twoje equals()
nie potrzebuje takiego stwierdzenia jak if (this == obj)
. Nigdy się nie wydarzy.
Zamiast if (getClass() != obj.getClass())
w twoim equals()
lepiej Użyj if (!(obj instanceof this))
. Będzie on ważny nawet dla podklas.
Więc jedyne co trzeba porównać to w rzeczywistości X i Y. więc najlepszą equals()
implementacją w tym przypadku byłoby:
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;
}
Więc w końcu twoja kluczowa klasa jest jak to:
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;
}
}
Możesz nadać indeksom wymiarów X
i Y
publiczny poziom dostępu, ze względu na to, że są ostateczne i nie zawierają poufnych informacji. Nie jestem w 100% pewien, czy private
poziom dostępu działa poprawnie w w każdym przypadku podczas rzucania Object
na Key
.
Jeśli zastanawiasz się nad finałami, deklaruję wszystko jako ostateczne, która wartość jest ustawiona na instancjach i nigdy się nie zmienia - a zatem jest stałą obiektową.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-23 22:37:57
Nie możesz mieć mapy hashowej z wieloma kluczami, ale możesz mieć obiekt, który przyjmuje wiele parametrów jako klucz.
Utwórz obiekt o nazwie Index, który przyjmuje wartości x i 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;
}
}
Następnie mieć HashMap<Index, Value>
, Aby uzyskać wynik. :)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-06 05:58:47
Dwie możliwości. Albo użyj kombinowanego klucza:
class MyKey {
int firstIndex;
int secondIndex;
// important: override hashCode() and equals()
}
Lub mapa mapy:
Map<Integer, Map<Integer, Integer>> myMap;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-03 22:24:10
Zaimplementowane w common-collections [MultiKeyMap] (https://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/map/MultiKeyMap.html)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-20 02:51:51
Utwórz klasę wartości, która będzie reprezentować Twój klucz złożony, na przykład:
class Index2D {
int first, second;
// overrides equals and hashCode properly here
}
Dbanie o poprawne nadpisanie equals()
i hashCode()
. Jeśli wydaje się to dużo pracy, możesz rozważyć kilka gotowych kontenerów generycznych, takich jak Pair
dostarczanych między innymi przez Apache commons.
Istnieje również wiele podobnych pytań tutaj, z innymi pomysłami, takimi jak użycie tabeli , chociaż pozwala na różne typy kluczy, co może być przesadą (w wykorzystanie pamięci i złożoność) w Twoim przypadku, ponieważ rozumiem, że Twoje klucze są zarówno liczbami całkowitymi.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:28
Jeśli są to dwie liczby całkowite, możesz spróbować szybkiej i brudnej sztuczki: Map<String, ?>
używając klucza jako i+"#"+j
.
Jeśli klucz i+"#"+j
jest taki sam jak j+"#"+i
Spróbuj min(i,j)+"#"+max(i,j)
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-24 10:03:28
Możesz utworzyć swój kluczowy obiekt w następujący sposób:
Public class 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;
}
}
Zaletą tego jest to, że zawsze upewni się, że pokrywasz również wszystkie scenariusze równości.
Uwaga: Twoje kluczy1 i kluczy2 powinny być niezmienne. Tylko wtedy będziesz w stanie zbudować stabilny kluczowy obiekt.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-10 17:29:25
Możemy utworzyć klasę przekazującą więcej niż jeden klucz lub wartość, a obiekt tej klasy może być użyty jako parametr w 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();
}
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-25 13:33:49
Użyj Pair
jako klucza HashMap
. JDK nie ma pary, ale możesz użyć biblioteki stron trzecich, takiej jak http://commons.apache.org/lang lub napisz parę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-03 22:25:10
Możesz również użyć implementacji guava Table.
Tabela przedstawia specjalną mapę, na której można podać dwa klucze w sposób kombinowany, aby odnosić się do pojedynczej wartości. Jest to podobne do tworzenia mapy map.
//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");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-14 12:56:04