简体   繁体   中英

Two way collections in Java

I have a list of objects. The objects are given an ID and stored in a Hashtable. If I need an object with particular ID, I simply say:

ht.get(ID);

However, sometimes I need to get the ID for a given object:

ht.get(Object);

My first idea is to use two different HashTables; one for ID -> Object mapping and the other for Object -> ID mapping.

Does this sound like a good enough solution?

If you cannot use external collections (as you seem to not want to use given one of your comments) you could write a simple class to do what you want (which, yes, is essentially your first thought), along the lines of (I didn't compile this, and it is just a first thought so could be a bad idea, etc ...):

EDIT: now there are two versions, one that allows for duplicate values and one that does not. The ones that does not will remove the key if the value is overwritten.

This version does not allow duplicate values:

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"));
    }
}

This version allows duplicated values and gives you back a list of all of the keys that have a given value:

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"));
    }
}

Hiding the two maps in a class is a good idea, because of you find a better way later all you need to do is replace the innards of the class and the rest of your code is left untouched.

如果使用外部库是正常的,您应该在google集合上查看BiMap: http//google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/BiMap.html

What you are looking for is a bidirectional map. You can find it in the commons collections in the classes implementing the BidiMap interface or the Google Guava .

What you are looking for is a Bi-directional Map. Try Apache Collections BidiMap.

http://commons.apache.org/collections/api-3.1/org/apache/commons/collections/BidiMap.html

Not that I know of immediatley but you can build one ... How about having a single collection of your objects and several lookup structures (hashmaps or trees) that don't store the objects themselves (for memory saving reasons) but the index into your single collection? This way you use the appropriate lookup structure you need (Id -> object or vice versa) get back an integer value that you can index into your original collection. This way you can do more than a bidirectional lookup in case you need to do so in the future.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM