2010-07-07 35 views
4

我有一個對象列表。對象被賦予一個ID並存儲在一個Hashtable中。如果我需要有特定ID的對象,我只是說:Java中的雙向集合

ht.get(ID); 

不過,有時我需要的ID給定對象:

ht.get(Object); 

我最初的想法是使用兩個不同的哈希表;一個用於ID - >對象映射,另一個用於對象 - > ID映射。

這聽起來像是一個足夠好的解決方案嗎?

+0

這隻有在HashTables相當靜態時纔有用。如果你有很多更新的表,這個方法需要更新兩個HashTables – 2010-07-07 22:56:30

+1

通常(通常是?)ID是對象本身的一部分,所以後者變成'object.getId()'。或者在你的情況下不適合? – doublep 2010-07-07 22:58:57

+0

他們經常更新!兩張桌子似乎對我來說是骯髒的解決方案...但是..好吧.. – user318247 2010-07-07 23:01:41

回答

8

如果你不能使用外部集合(因爲你似乎不想使用給定的一個評論),你可以寫一個簡單的類來做你想做的事(這是的,實質上是你的第一個想法),沿着(我沒有編譯這個,這只是第一個想法,所以可能是一個壞主意,等等......):

編輯:現在有兩個版本,一個允許重複值和一個那不。如果值被覆蓋,那些不會刪除密鑰的。

這個版本不允許重複的值:

class Foo<K, V> 
{ 
    private final Map<K, V> keyValue; 
    private final Map<V, K> valueKey; 

    { 
     keyValue = new HashMap<K, V>(); 
     valueKey = new HashMap<V, K>(); 
    } 

    // this makes sure that if you do not have duplicate values. 
    public void put(final K key, final V value) 
    { 
     if(keyValue.containsValue(value)) 
     { 
      keyValue.remove(valueKey.get(value)); 
     } 

     keyValue.put(key, value); 
     valueKey.put(value, key); 
    } 

    public V getValueForKey(final K key) 
    { 
     return (keyValue.get(key)); 
    } 

    public K getKeyForValue(final V value) 
    { 
     return (valueKey.get(value)); 
    } 

    public static void main(final String[] argv) 
    { 
     Foo<String, String> foo; 

     foo = new Foo<String, String>(); 
     foo.put("a", "Hello"); 
     foo.put("b", "World"); 
     foo.put("c", "Hello"); 

     System.out.println(foo.getValueForKey("a")); 
     System.out.println(foo.getValueForKey("b")); 
     System.out.println(foo.getValueForKey("c")); 

     System.out.println(foo.getKeyForValue("Hello")); 
     System.out.println(foo.getKeyForValue("World")); 
    } 
} 

該版本允許重複值,給你回所有具有給定值的所有鍵的列表:

class Foo<K, V> 
{ 
    private final Map<K, V> keyValue; 
    private final Map<V, List<K>> valueKeys; 

    { 
     keyValue = new HashMap<K, V>(); 
     valueKeys = new HashMap<V, List<K>>(); 
    } 

    public void put(final K key, final V value) 
    { 
     List<K> values; 

     keyValue.put(key, value); 

     values = valueKeys.get(value); 

     if(values == null) 
     { 
      values = new ArrayList<K>(); 
      valueKeys.put(value, values); 
     } 

     values.add(key); 
    } 

    public V getValueForKey(final K key) 
    { 
     return (keyValue.get(key)); 
    } 

    public List<K> getKeyForValue(final V value) 
    { 
     return (valueKeys.get(value)); 
    } 

    public static void main(final String[] argv) 
    { 
     Foo<String, String> foo; 

     foo = new Foo<String, String>(); 
     foo.put("a", "Hello"); 
     foo.put("b", "World"); 
     foo.put("c", "Hello"); 

     System.out.println(foo.getValueForKey("a")); 
     System.out.println(foo.getValueForKey("b")); 
     System.out.println(foo.getValueForKey("c")); 

     System.out.println(foo.getKeyForValue("Hello")); 
     System.out.println(foo.getKeyForValue("World")); 
    } 
} 

隱藏在一個類中的兩個地圖是一個好主意,因爲你後來發現了一個更好的方法,所有你需要做的就是替換這個類的內部,而你的代碼的其餘部分保持不變。

+0

完美的答案。對於Java新手來說,注意集合不僅僅是索引 - 它們不重複信息,只包含對它的引用。這意味着此解決方案不會複製包含的任何信息,它只包含兩個散列索引,這是此問題的最佳解決方案。 – 2010-07-07 23:20:04

+0

這不能正常工作。您應該注意,相同的值不會插入到地圖中。考慮 myFoo.put(「a」,「foo」); myFoo.put(「b」,「foo」); – 2010-07-08 18:36:09

+0

我確實考慮過這一點,但忘記了它會使其中一個地圖與另一個地圖不一致。我通過兩種方式修復了它(我相信),其中一個刪除無效密鑰,另一個使用列表維護重複項。 – TofuBeer 2010-07-08 18:59:35

0

不,我知道immediatley的,但你可以建立一個...如何讓你的對象和幾個查找結構(包含HashMap或樹)不存儲對象本身的一個集合(爲了記憶保存的原因),但索引到你的單一集合?通過這種方式,您可以使用您需要的適當的查找結構(Id - >對象或反之亦然)獲取可以索引到原始集合中的整數值。這樣,您可以做的不僅僅是雙向查找,以防將來需要這樣做。