オブジェクトのグループを hashmap に格納したいと思います。キーは 2 つの文字列値の合成になります。これを達成する方法はありますか?
私は単に2つの文字列を連結することができますが、これを行うためのより良い方法があると確信しています.
オブジェクトのグループを hashmap に格納したいと思います。キーは 2 つの文字列値の合成になります。これを達成する方法はありますか?
私は単に2つの文字列を連結することができますが、これを行うためのより良い方法があると確信しています.
次の 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();
}
}
車輪を再発明する必要はありません。必要に応じて、 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
ハッピーコーディング!
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とは異なるキーですか?)。
私も似たようなケースがあります。チルダ ( ~ ) で区切られた 2 つの文字列を連結するだけです。
したがって、クライアントがサービス関数を呼び出してマップからオブジェクトを取得すると、次のようになります。
MyObject getMyObject(String key1, String key2) {
String cacheKey = key1 + "~" + key2;
return map.get(cachekey);
}
シンプルですが、うまくいきます。
スパゲッティ/サボテンスタックについて読んで、この目的に役立つバリアントを思いつきました。これには、キーを任意の順序でマッピングして、 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
}
}
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