36

オブジェクトのグループを hashmap に格納したいと思います。キーは 2 つの文字列値の合成になります。これを達成する方法はありますか?

私は単に2つの文字列を連結することができますが、これを行うためのより良い方法があると確信しています.

4

9 に答える 9

53

次の 2 つの文字列を含むカスタム オブジェクトを作成できます。

class StringKey {
    private String str1;
    private String str2;
}

問題は、そのような 2 つのオブジェクトの等価性テストとハッシュ コードを決定する必要があることです。

同等性は両方の文字列で一致する可能性があり、ハッシュコードは連結されたメンバーのハッシュコードである可能性があります (これは議論の余地があります)。

class StringKey {
    private String str1;
    private String str2;

    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj instanceof StringKey) {
            StringKey s = (StringKey)obj;
            return str1.equals(s.str1) && str2.equals(s.str2);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return (str1 + str2).hashCode();
    }
}
于 2012-07-28T11:38:01.960 に答える
13

車輪を再発明する必要はありません。必要に応じて、 GuavaのインターフェイスのHashBasedTable<R,C,V>実装を使用するだけです。Table<R,C,V>ここに例があります

Table<String, String, Integer> table = HashBasedTable.create();

table.put("key-1", "lock-1", 50);
table.put("lock-1", "key-1", 100);

System.out.println(table.get("key-1", "lock-1")); //prints 50
System.out.println(table.get("lock-1", "key-1")); //prints 100

table.put("key-1", "lock-1", 150); //replaces 50 with 150

ハッピーコーディング!

于 2016-07-07T10:24:30.647 に答える
8

Pairメンバーとして 2 つの文字列を含む(たとえば) オブジェクトを作成し、これをキーとして使用してみませんか?

例えば

public class Pair {
   private final String str1;
   private final String str2;

   // this object should be immutable to reliably perform subsequent lookups
}

equals()hashCode( ) を忘れないでください。不変性要件の背景など、HashMap とキーの詳細については、このブログ エントリを参照してください。キーが不変でない場合は、そのコンポーネントを変更でき、その後のルックアップでキーを見つけることができません (これが、 などの不変オブジェクトがStringキーの候補として適している理由です)。

連結は理想的ではないというのは正しいです。状況によっては動作しますが、信頼性が低く脆弱なソリューションであることがよくあります (たとえば、AB/CはA/BCとは異なるキーですか?)。

于 2012-07-28T11:36:59.353 に答える
5

私も似たようなケースがあります。チルダ ( ~ ) で区切られた 2 つの文字列を連結するだけです。

したがって、クライアントがサービス関数を呼び出してマップからオブジェクトを取得すると、次のようになります。

MyObject getMyObject(String key1, String key2) {
    String cacheKey = key1 + "~" + key2;
    return map.get(cachekey);
}

シンプルですが、うまくいきます。

于 2012-07-28T12:06:25.923 に答える
2

スパゲッティ/サボテンスタックについて読んで、この目的に役立つバリアントを思いつきました。これには、キーを任意の順序でマッピングして、 map.lookup("a","b") および map.lookup(" b","a") は同じ要素を返します。また、2 つだけでなく、任意の数のキーでも機能します。

私はデータフロー プログラミングを実験するためのスタックとして使用しますが、マルチ キー マップとして機能する簡単で汚いバージョンを次に示します (改善する必要があります: 配列の代わりにセットを使用して、重複するキーの出現を検索しないようにする必要があります)。

public class MultiKeyMap <K,E> {
    class Mapping {
        E element;
        int numKeys;
        public Mapping(E element,int numKeys){
            this.element = element;
            this.numKeys = numKeys;
        }
    }
    class KeySlot{
        Mapping parent;
        public KeySlot(Mapping mapping) {
            parent = mapping;
        }
    }
    class KeySlotList extends LinkedList<KeySlot>{}
    class MultiMap extends HashMap<K,KeySlotList>{}
    class MappingTrackMap extends HashMap<Mapping,Integer>{}

    MultiMap map = new MultiMap();

    public void put(E element, K ...keys){
        Mapping mapping = new Mapping(element,keys.length);
        for(int i=0;i<keys.length;i++){
            KeySlot k = new KeySlot(mapping);
            KeySlotList l = map.get(keys[i]);
            if(l==null){
                l = new KeySlotList();
                map.put(keys[i], l);
            }
            l.add(k);
        }
    }
    public E lookup(K ...keys){
        MappingTrackMap tmp  = new MappingTrackMap();
        for(K key:keys){
            KeySlotList l = map.get(key);
            if(l==null)return null;
            for(KeySlot keySlot:l){
                Mapping parent = keySlot.parent;
                Integer count = tmp.get(parent);
                if(parent.numKeys!=keys.length)continue;
                if(count == null){
                    count = parent.numKeys-1;
                }else{
                    count--;
                }
                if(count == 0){
                    return parent.element;
                }else{
                    tmp.put(parent, count);
                }               
            }
        }
        return null;
    }
    public static void main(String[] args) {
        MultiKeyMap<String,String> m = new MultiKeyMap<String,String>();
        m.put("brazil", "yellow", "green");
        m.put("canada", "red", "white");
        m.put("USA", "red" ,"white" ,"blue");
        m.put("argentina", "white","blue");

        System.out.println(m.lookup("red","white"));  // canada
        System.out.println(m.lookup("white","red"));  // canada
        System.out.println(m.lookup("white","red","blue")); // USA
    }
}
于 2014-06-04T17:14:43.240 に答える
1
public static String fakeMapKey(final String... arrayKey) {
    String[] keys = arrayKey;

    if (keys == null || keys.length == 0)
        return null;

    if (keys.length == 1)
        return keys[0];

    String key = "";
    for (int i = 0; i < keys.length; i++)
        key += "{" + i + "}" + (i == keys.length - 1 ? "" : "{" + keys.length + "}");

    keys = Arrays.copyOf(keys, keys.length + 1);

    keys[keys.length - 1] = FAKE_KEY_SEPARATOR;

    return  MessageFormat.format(key, (Object[]) keys);}
public static string FAKE_KEY_SEPARATOR = "~";

入力: fakeMapKey("keyPart1","keyPart2","keyPart3");
出力: keyPart1~keyPart2~keyPart3
于 2013-03-15T15:10:51.300 に答える