Barry Fruitman
Barry Fruitman

Reputation: 12664

How do I retrieve a key object from a Map?

Take two instances of the same class A, called foo and bar, where:

foo != bar
foo.equals(bar) == true

In other words, foo and bar are different instances but with the same hash code. Now take an instance of Map<A,B> called "map", where foo is a key in map. Is it possible to retrieve foo from Map, using bar? Currently I iterate through the key set and compare every key but is there a faster way? There don't seem to be any methods in Map for retrieving keys.

I am willing to try any data structure that implements Map or can work like a map.

Why do I want to do this? I'm trying to avoid retaining any more instances than necessary. Once I find foo I can release bar.

Thanks in advance...

Upvotes: 4

Views: 164

Answers (5)

Catalin Pol
Catalin Pol

Reputation: 261

Just using the existing map to find duplicztes doesn't seem to be enough. Use a second map, where you put(key,key) pairs. Then:

  • map.get(key) == null if the key is not already there
  • map.get(key) == firstObjectAllocated otherwise

Upvotes: 1

Lifecube
Lifecube

Reputation: 1188

You can refer to the source code of HashMap

If based on your implementation: foo.hashCode() == bar.hashCode() and foo.equals(bar)

Then, yes you could directly get the value for key foo by map.get(bar)


updated: sorry misunderstanding your question before
if you want to keep the key, why you don't just keep the key cached. Then to retrieve the key is hash tree mapping, should be fast.

HashMap<K,V> map = new HashMap<K,V>();
HashMap<K,K> cacheKeys = new HashMap<K,K>();
cacheKeys.put(foo,foo);
map.put(foo,value);

//now you have var bar; you could retrieve the cached key
bar = cacheKeys.get(bar);//this will make bar = foo; the real bar will be gc
//then get the value 
val = map.get(bar);

Upvotes: 0

Radiodef
Radiodef

Reputation: 37875

HashMap actually does have a method to retrieve the entry but it is package-private. I am not really sure why it isn't public to be honest. I don't think it exposes anything. You can, of course, call it with reflection.

Map<String, String> map = new HashMap<String, String>();
map.put(new String("hello"), "world!");

Method method = (
    HashMap.class.getDeclaredMethod("getEntry", Object.class)
);
method.setAccessible(true);

@SuppressWarnings("unchecked")
Map.Entry<String, String> entry = (Map.Entry<String, String>)(
    method.invoke(map, new String("hello"))
);

System.out.println(entry.toString().replace("=", " ")); // hello world

The reflection probably makes it not useful in the scenario you've described but I guess it could be useful to others. I wouldn't recommend using it.

Upvotes: 1

Aniket Kulkarni
Aniket Kulkarni

Reputation: 12993

You can use Apache Commons Collections ™. It has Bidirectional Maps BidiMap.
These represent maps where the key can lookup the value and the value can lookup the key with equal ease.

BidiMap bidi = new TreeBidiMap();
bidi.put("SIX", "6");
bidi.get("SIX");  // returns "6"
bidi.getKey("6");  // returns "SIX"
bidi.removeValue("6");  // removes the mapping
BidiMap inverse = bidi.inverseBidiMap();  // returns a map with keys and values swapped

See also

Upvotes: 1

Ruchira Gayan Ranaweera
Ruchira Gayan Ranaweera

Reputation: 35587

This way may faster.

   Iterator<A> mapKeyIterator=map.keySet().iterator();
    while (mapKeyIterator.hasNext()){
        A key;
        if((key=mapKeyIterator.next()).equals(bar)) {
            return key;
        }
    }

Upvotes: 0

Related Questions