132

整数の2D配列があります。それらをHashMapに入れてほしい。しかし、配列インデックスに基づいてHashMapから要素にアクセスしたいと思います。何かのようなもの:

A [2] [5]map.get(2,5)の場合、そのキーに関連付けられた値を返します。しかし、キーのペアを使用してハッシュマップを作成するにはどうすればよいですか?または、一般的に、複数のキー: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;
4

14 に答える 14

208

いくつかのオプションがあります:

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 = //...

しかし、それは、パフォーマンスの観点からも、読みやすさと正確さの観点からもひどいものです(リストのサイズを強制する簡単な方法はありません)。

タプルとクラスがあるScalaを見てください(クラス全体をワンライナーcaseに置き換えます)。Key

于 2013-02-03T22:25:35.787 に答える
26

独自のキーペアオブジェクトを作成するときは、いくつかの問題に直面する必要があります。

まず、との実装に注意する必要がhashCode()ありequals()ます。これを行う必要があります。

次に、実装するときはhashCode()、それがどのように機能するかを理解していることを確認してください。与えられたユーザー例

public int hashCode() {
    return this.x ^ this.y;
}

実際には、実行できる最悪の実装の1つです。理由は単純です。同じハッシュがたくさんあります。そして、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パブリックアクセスレベルは最終的なものであり、機密情報が含まれていないため、これらを指定できます。にキャストするときに、アクセスレベルがどのような場合でも正しくprivate機能するかどうかは、100%わかりません。ObjectKey

ファイナルについて疑問がある場合は、インスタンス化時に設定され、変更されない値をファイナルとして宣言します。したがって、オブジェクト定数です。

于 2014-11-17T21:02:29.990 に答える
7

複数のキーを持つハッシュマップを持つことはできませんが、キーとして複数のパラメーターを受け取るオブジェクトを持つことはできます。

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>、結果を取得する必要があります。:)

于 2013-02-03T22:25:36.083 に答える
7

common -collectionsMultiKeyMapに実装されています

于 2014-11-25T08:33:41.917 に答える
4

2つの可能性。組み合わせたキーを使用します。

class MyKey {
    int firstIndex;
    int secondIndex;
    // important: override hashCode() and equals()
}

または地図の地図:

Map<Integer, Map<Integer, Integer>> myMap;
于 2013-02-03T22:24:10.717 に答える
4

Pairのキーとしてを使用しますHashMapJDKにはPairはありませんが、 http: //commons.apache.org/langなどのサードパーティのlibrarayを使用するか、独自のPairtaypeを作成することができます。

于 2013-02-03T22:25:10.153 に答える
2

Java 7+には、Map.Entry<K,V>マップ(またはセットのエントリ)のキーとして使用できる新しいクラスが含まれています。Map.entry(K k, V v)また、新しいMap.Entryオブジェクトを簡単に作成するためのメソッドも含まれています。

使用法:

Map<Map.Entry<Integer,Integer>, Integer> map = new HashMap<>();
map.put(Map.entry(1, 2), 0);

Pair<K, V>javafx.utilにもあります

Map<Pair<Integer,Integer>, Integer> map = new HashMap<>();
map.put(new Pair(1, 2), 0);
于 2021-08-02T03:50:20.173 に答える
1

それらが2つの整数である場合はMap<String, ?>、キーをとして使用するという簡単で汚いトリックを試すことができますi+"#"+j

キーがtryとi+"#"+j同じ場合。j+"#"+imin(i,j)+"#"+max(i,j)

于 2013-02-03T22:29:54.210 に答える
1

次のような複合キーを表す値クラスを作成します。

class Index2D {
  int first, second;

  // overrides equals and hashCode properly here
}

オーバーライドequals()してhashCode()正しくするように注意してください。Pairそれが大変な作業のように思われる場合は、特にapachecommonsによって提供されるような既製の汎用コンテナーを検討することをお勧めします。

ここにも同様の質問がたくさんありますが、Guavaのテーブルを使用するなど、他のアイデアもありますが、キーのタイプを変えることができます。これは、キーが両方とも整数であることを理解しているため、(メモリの使用と複雑さにおいて)やり過ぎになる可能性があります。

于 2013-02-03T22:24:40.103 に答える
1

次のようなキーオブジェクトを作成できます。

パブリッククラス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は不変である必要があります。そうして初めて、安定したキーオブジェクトを構築できるようになります。

于 2015-02-24T19:58:53.420 に答える
1

これには、 guavaTableの実装を使用することもできます。

表は、単一の値を参照するために2つのキーを組み合わせて指定できる特別なマップを表しています。これは、マップのマップを作成するのと似ています。

//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");
于 2016-12-14T12:56:04.033 に答える
1

複数のキーまたは値を渡すクラスを作成でき、このクラスのオブジェクトをマップのパラメーターとして使用できます。

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();

        }

    }

    }

 }
于 2017-05-25T13:33:49.987 に答える
0

以下のリンクからダウンロードできます: https ://github.com/VVS279/DoubleKeyHashMap/blob/master/src/com/virtualMark/doubleKeyHashMap/DoubleKeyHashMap.java

https://github.com/VVS279/DoubleKeyHashMap

ダブルキーを使用できます:値ハッシュマップ、

   DoubleKeyHashMap<Integer, Integer, String> doubleKeyHashMap1 = new 
   DoubleKeyHashMap<Integer, Integer, String>();

   DoubleKeyHashMap<String, String, String> doubleKeyHashMap2 = new 
   DoubleKeyHashMap<String, String, String>();
于 2019-08-20T09:30:51.647 に答える
0

org.apache.commons.lang3.tuple.Pairの使用は非常に簡単です。

   Map<String, Pair<String, Integer>> map= new HashMap<>(); 
   map.put("key", Pair.of("a", 1)); 
   int value = map.get("key").getRight();
   
于 2021-12-21T19:59:49.540 に答える