2010-07-07 2 views
4

개체 목록이 있습니다. 객체에는 ID가 주어지며 Hashtable에 저장됩니다. 나는 특정 ID와 객체가 필요한 경우, 단순히 말 :Java의 양방향 컬렉션

ht.get(ID); 

을하지만, 때로는 주어진 객체의 ID를 얻을 필요가 :

ht.get(Object); 

내 첫번째 생각은 두 개의 서로 다른 해시 테이블을 사용하는 것입니다 ; 하나는 ID -> 오브젝트 맵핑이고 다른 하나는 오브젝트 -> ID 맵핑입니다.

충분한 해결책이 들리니? 외부 라이브러리를 사용하여 OK 경우

+0

해시 테이블이 상당히 정적 인 경우에만 유용합니다. 테이블에 대한 업데이트가 많은 경우이 메소드는 두 개의 HashTable을 업데이트해야합니다. –

+1

일반적으로 (종종?) ID는 객체 자체의 일부이므로 후자는'object.getId()'가됩니다. 또는 귀하의 경우에 적절하지 않습니까? – doublep

+0

그들은 매우 자주 업데이트됩니다! 두 테이블이 나에게 더러운 해결책처럼 보입니다 ...하지만 .. 음 .. – user318247

답변

8

외부 컬렉션을 사용할 수없는 경우 (주어진 의견을 사용하고 싶지 않으므로) 원하는대로 할 수있는 간단한 수업을 작성할 수 있습니다 (예 : 본질적으로 첫 번째 생각입니다). 라인의 (나는 이것을 컴파일하지 않았고 그것은 처음 생각 이었으므로 나쁜 아이디어 일 수있다.) :

EDIT : 중복 된 값을 허용하는 버전과 하나의 중복 된 버전이있다. 그렇지 않습니다. 값을 덮어 쓰지 않으면 키가 제거되지 않습니다.

이 버전은 중복 값을 허용하지 않습니다

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에 익숙하지 않은 사람들은 컬렉션이 인덱스 이상이라는 것을 알아두면 유용합니다. 정보를 복제하지 않고 참조 만 포함하는 것입니다. 즉,이 솔루션은 포함 된 정보를 복제하지 않으며 단순히이 문제에 대한 최적의 솔루션 인 두 개의 해시 색인을 포함합니다. –

+0

제대로 작동하지 않습니다. 동일한 값이지도에 삽입되지 않도록주의해야합니다. 고려하십시오 myFoo.put ("a", "foo"); myFoo.put ("b", "foo"); –

+0

나는 이것을 고려했다. 그러나지도 중 하나가 다른지도와 모순된다는 사실을 잊었다. 나는 두 가지 방법으로 그것을 고쳤다. 하나는 유효하지 않은 키를 제거하고 다른 하나는 중복을 유지하기 위해리스트를 사용한다. – TofuBeer

2

, 당신이 구글에서 컬렉션에 BiMap를 확인해야합니다 : http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/BiMap.html

+0

외부 라이브러리를 사용하지 않고 있습니다. 제가 운명 지요? – user318247

+0

언제든지 직접 구현할 수 있습니다. 가장 일반적인 방법은 2 개의 해시 테이블을 사용하고 동기화하는 것입니다. AbstractBiMap의 출처를 Google 콜렉션에서 살펴볼 수있는 몇 가지 아이디어를 얻을 수 있습니다. – bashflyng

0

나는 immediatley 알고하지 않는 것이하지만 당신은 하나를 ... 어떻게 객체와 여러 조회 구조 객체 자체를 저장하지 않는 (HashMaps을 또는 나무)의 단일 집합을 가진 약 (구축 할 수 있습니다 메모리 절약 이유로)하지만 귀하의 단일 컬렉션에 색인? 이렇게하면 필요한 조회 구조 (Id -> object 또는 그 반대로)를 사용하여 원본 컬렉션에 인덱스 할 수있는 정수 값을 얻을 수 있습니다. 이 방법을 사용하면 앞으로 필요할 때를 대비하여 양방향 조회 이상을 수행 할 수 있습니다.