정수의 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;
답변
몇 가지 옵션이 있습니다.
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 = //...
그러나 그것은 성능 측면에서 끔찍할뿐만 아니라 가독성과 정확성 (목록 크기를 적용하는 쉬운 방법이 없음)도 마찬가지입니다.
튜플과 case
클래스 가있는 Scala를 살펴볼 수도 있습니다 (전체 Key
클래스를 한 줄로 대체 ).
답변
고유 한 키 페어 객체를 생성 할 때 몇 가지 문제에 직면해야합니다.
먼저 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()
그것이 무엇을 위해 사용되는지 알고 키가 객체이기 때문에 키를 만드는 방법을 알고 있어야합니다. 진술로 인해 항상 동일한 결과를 얻을 수 있다면 종종 불필요합니다.
이와 같은 키를 생성하는 경우 : 키 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
공개 액세스 수준은 최종 항목이고 민감한 정보를 포함하지 않기 때문에 제공 할 수 있습니다 . 나는 확실히 여부를 100 % 아니에요 private
액세스 수준이 제대로 작동 어떤 을 캐스팅 할 때 경우 Object
A를 Key
.
파이널에 대해 궁금하다면 인스턴스에 설정되고 절대 변경되지 않는 값을 final로 선언하므로 객체 상수입니다.
답변
여러 키가있는 해시 맵을 가질 수 없지만 여러 매개 변수를 키로 사용하는 객체를 가질 수 있습니다.
x 및 y 값을 사용하는 Index라는 개체를 만듭니다.
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;
답변
에 Pair
대한 키로 사용하십시오 HashMap
. JDK에는 Pair가 없지만 http://commons.apache.org/lang 과 같은 타사 라이브러리를 사용하거나 직접 Pair taype를 작성할 수 있습니다.