Powinieneś użyć java.awt.Dimension jako klucza.
Klucz wymiarowy = nowy wymiar (4, 12);
Wymiar ma bardzo ładną metodę hashCode(), która generuje inny kod skrótu dla każdej pary liczb całkowitych dodatnich, tak aby kody mieszające dla (4, 12) i (12, 4) były różne. Tak więc są one szybkie do tworzenia instancji i tworzenia bardzo dobrych kodów hash.
Żałuję, że nie uczyniły klasy niezmienną, ale możesz stworzyć własną niezmienną klasę wzorowaną na Wymiarach.
Oto tabelę hashCode dla różnych wartości szerokości i wysokości:
0 1 2 3 4 <-- width
+--------------------
0 | 0 2 5 9 14
1 | 1 4 8 13
2 | 3 7 12
3 | 6 11
4 | 10
^
|
height
Jeśli zastosujemy hashCodes w kolejności od 0 do 14, zobaczysz wzór.
Oto kod, który wywołuje tę hashCode:
public int hashCode() {
int sum = width + height;
return sum * (sum + 1)/2 + width;
}
Można rozpoznać wzór na liczbę trójkątną wewnątrz ostatniej linii. Dlatego pierwsza kolumna tabeli zawiera wszystkie liczby trójkątne.
Aby uzyskać prędkość, należy obliczyć kod haszowania w konstruktorze. Więc cała klasa może wyglądać następująco:
public class PairHash {
private final int hash;
public PairHash(int a, int b) {
int sum = a+b;
hash = sum * (sum+1)/2 + a;
}
public int hashCode() { return hash; }
}
Oczywiście, jeśli będzie potrzebne równości metodę, ale ograniczyć się do liczb całkowitych dodatnich, które nie przepełnienia, można dodać bardzo szybko jeden:
Ograniczamy to do wartości dodatnich, ponieważ wartości ujemne spowodują pojawienie się zduplikowanych kodów skrótu. Ale z tym ograniczeniem, są to najszybsze metody hashCode() i equals(), które można zapisać. (Oczywiście, możesz napisać hashCodes równie szybko w każdej niezmiennej klasie, obliczając kod haszujący w konstruktorze.)
Jeśli nie możesz żyć z tymi ograniczeniami, po prostu zapisz parametry.
public class PairHash {
private final int a, b, hash;
public PairHash(int a, int b) {
this.a = a;
this.b = b;
int sum = a+b;
hash = sum * (sum+1)/2 + a;
}
public int hashCode() { return hash; }
public boolean equals(Object other) {
if (other instanceof PairHash) {
PairHash otherPair = (PairHash)other;
return a == otherPair.a && b == otherPair.b;
}
return false;
}
Ale tutaj jest kopacz. W ogóle nie potrzebujesz tej klasy. Ponieważ formuła daje unikalną liczbę całkowitą dla każdej pary liczb, możesz po prostu użyć tej liczby całkowitej jako klucza mapy. Klasa Integer ma własne metody szybkiego equals() i hashCode, które będą działały poprawnie. Ta metoda wygeneruje skrót z dwóch krótkich wartości. Ograniczeniem jest to, że twoje dane wejściowe muszą być dodatnimi krótkimi wartościami. Gwarantuje to, że nie będzie przepełnienia, a odlewanie sumy pośredniej na długą, ma szerszy zakres niż poprzednia metoda: Działa ze wszystkimi dodatnimi krótkimi wartościami.
static int hashKeyFromPair(short a, short b) {
assert a >= 0;
assert b >= 0;
long sum = (long) a + (long) b;
return (int) (sum * (sum + 1)/2) + a;
}
Myślę, że ciąg znaków rozdzielany przecinkami to dobry pomysł. Używam tego podejścia przez cały czas. – mob