lol
lol

Reputation: 3390

1 to 1 mapping in HashMap

I am across situation where I will be changing key based on value in HashMap. My HashMap is:

HashMap<Key, Path>

Initially I am creating Keys for each directory Path and putting these entries in HashMap. When doing processing, I will take Path based on Key from HashMap and process them. In some cases I will be re-calculating Key for some Path and want to replace old Key with new Key for that Path. I want to keep unique Keys for unique Paths and update Entry in HashMap with either one. So I want to perform reverse of HashMap to update Key. What is best technique for this?

Thanks in Advance.

Upvotes: 0

Views: 3903

Answers (7)

chaoticflow
chaoticflow

Reputation: 61

Needed a solution this recently, but didn't want to rely on a plugin, so I extended the base Java class. This implementation does not allow null values.

public class OneToOneMap<K,V> extends HashMap<K,V> {
    public OneToOneMap() {
        super();
    }
    public OneToOneMap(int initialCapacity) {
        super(initialCapacity);
    }
    public OneToOneMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
    }
    public OneToOneMap(Map<? extends K, ? extends V> m) {
        super(m);
        dedup();
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m){
        super.putAll(m);
        dedup();
    }

    @Override
    public V put(K key, V value) {
        if( key == null || value == null ) return null;
        removeValue(value);
        return super.put(key,value);
    }

    public K getKey( V value ){
        if( value == null || this.size() == 0 ) return null;
        Set<K> keys = new HashSet<>();
        keys.addAll(keySet());
        for( K key : keys ){
            if( value.equals(get(key) )) return key;
        }
        return null;
    }
    public boolean hasValue( V value ){
        return getKey(value) != null;
    }
    public boolean hasKey( K key ){
        return get(key) != null;
    }

    public void removeValue( V remove ){
        V value;
        Set<K> keys = new HashSet<>();
        keys.addAll(keySet());
        for( K key : keys ){
            value = get(key);
            if( value == null || key == null || value.equals(remove)) remove(key);
        }        
    }
    //can be used when a new map is assigned to clean it up
    public void dedup(){
        V value;
        Set<V> values = new HashSet<>();
        Set<K> keys = new HashSet<>();
        keys.addAll(keySet());
        for( K key : keys ){
            value = get(key);
            if( value == null || key == null || values.contains(value) ) remove(key);
            else values.add(value);
        }
    }
}

Upvotes: 0

user5070966
user5070966

Reputation:

Assuming the bidirectional hash is guaranteed to be 1-to-1 and there are no concerns of memory usage, this is a pure java solution.

public class BiHash<K> extends ConcurrentHashMap<K, K>  {

    public void biPut(K k1, K k2)
    {
        super.put(k1, k2);
        super.put(k2, k1);
    }

}

Upvotes: 0

Rohit Jain
Rohit Jain

Reputation: 213311

May be you are looking for Google Guava's BiMap.

A bimap (or "bidirectional map") is a map that preserves the uniqueness of its values as well as that of its keys. This constraint enables bimaps to support an "inverse view", which is another bimap containing the same entries as this bimap but with reversed keys and values.

Upvotes: 5

cowls
cowls

Reputation: 24344

If you want to update a key you could do this:

   String oldKey = "oldKey";
   String newKey = "newKey";

   map.put(newKey, map.remove(oldKey));

To get a key based on value you can either use:


For fun, here's how you could maintain two maps:

    Map<String, String> keyMap = new HashMap<String, String>();
    Map<String, String> valueMap = new HashMap<String, String>();

    String val = "someVal";
    keyMap.put("newKey", keyMap.remove(valueMap.get(val)));
    valueMap.put(val, "newKey");

Upvotes: 1

ameed
ameed

Reputation: 1160

When you want to set a new key, use

hm.set(newKey, oldPath);

where hm is your HashMap. Then, use

hm.remove(oldKey)

to remove the old key.

Note that if you could possibly have two Paths with the same Key, then you'll have to reverse your HashMap to <Path, Key>, since one Key would overwrite the other. To lookup a value and retrieve its key, use the entrySet() and loop through (update 1 to the linked post).

Hope this helps!

Upvotes: 0

I would

myHashMap.remove(Key);

then

myHashMap.put( newKey, new value);

During an iteration of the hashMap, the removal option is not allowe.

Upvotes: 0

Ivaylo Strandjev
Ivaylo Strandjev

Reputation: 70989

Add another HashMap to do the reverse mapping. Keep it in sync with the original map and that's it. I would even create a helper class that ensures all operations are synced between the two maps.

Upvotes: 3

Related Questions