[java] 두 개의 키 (Key-Pair, Value)로 HashMap을 만드는 방법은 무엇입니까?

정수의 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.

배열 인덱스는, 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 = //...

그러나 그것은 성능 측면에서 끔찍할뿐만 아니라 가독성과 정확성 (목록 크기를 적용하는 쉬운 방법이 없음)도 마찬가지입니다.

튜플과 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;
  }

}

차원 인덱스 XY공개 액세스 수준은 최종 항목이고 민감한 정보를 포함하지 않기 때문에 제공 할 수 있습니다 . 나는 확실히 여부를 100 % 아니에요 private액세스 수준이 제대로 작동 어떤 을 캐스팅 할 때 경우 ObjectA를 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를 작성할 수 있습니다.


답변

다음과 같이 복합 키를 나타내는 값 클래스를 만듭니다.

class Index2D {
  int first, second;

  // overrides equals and hashCode properly here
}

재정의 equals()하고 hashCode()올바르게. 이것이 많은 작업처럼 보인다면 Pair아파치 커먼즈에서 제공하는 것과 같은 기성품 일반 컨테이너를 고려할 수 있습니다.

Guava의 Table 사용과 같은 다른 아이디어와 함께 유사한 질문이 많이 있지만 키가 다른 유형을 가질 수 있습니다.