tags:

views:

117

answers:

5

I have a HashMap and now i need to find all the keys inside the HashMap which has a particular letter inside it and replace it with another letter

+1  A: 

So you want to change the Key. If the Hashalgorithm isn't something strange you'll have to get all key-value pairs, delete them from the hashmap, change them and reinsert them. Or insert them in a new Hashmap.

kasten
+3  A: 

You could try this :

public void replaceKeysChar(char originalChar, char newChar, Map<String, ?> map) {
    Map<String, Object> tempMap = new HashMap<String, Object>();
    for (Map.Entry<String, ?> entry : map.entrySet()) {
        String key = entry.getKey();
        if(key != null){
            key = key.replace(originalChar, newChar);
        }
        tempMap.put(key, entry.getValue());
    }
    map.clear();
    map.putAll(tempMap);
}

This way you handle only char, and you don't change the implementation. Plus when you iterate you don't add item in your map (it would be a bad idea).

If you don't care about the implementation simply return the tempMap and remove the clear/putAll part (it will consume less resources).

EDIT :

After @locka's answer I think I should specify that this method can't handle collisions.

If your Map contains the keys "toto" and "tata" and you do a `replaceKeysChar('a','o', map) only one of the values between "toto"'s value and "tata"'s value will be in the map, the other will simply be ignored.

EDIT bis:

To handle collisions with exceptions (à la @Stephen C) just replace the old for by this one :

    for (Map.Entry<String, ?> entry : map.entrySet()) {
        String key = entry.getKey();
        if(key != null){
            key = key.replace(originalChar, newChar);
        }
        if(tempMap.containsKey(key))
            throw new CollisionException();
        tempMap.put(key, entry.getValue());
    }
Colin Hebert
can u show an small example with above method, it would help me a lot
John
@John replaceKeysChar('k', 'j', yourMap); I don't see how could I be more explicit
Colin Hebert
@Colin Thanks for letting me know. Now i could think and thats your answer so deleted
org.life.java
+2  A: 
  1. Construct a new hashmap
  2. Copy all the (key,value) pairs from the old hashmap, except that you replace OLDCHAR with NEWCHAR in the keys
  3. Swap the hashmaps over.
Douglas Leeder
This solution is preferable to those that update the hashmap in-place. It's likely faster; easier to verify correct; and more flexibly usable (in situations where you want to keep the old hashmap).
Eamon Nerbonne
+1  A: 

I think people are concerned that you can't change a String key in situ because of immutability and the String's hashcode being tied the value of the string. Adding / removing keys could potentially work but then you run the risk of collisions, where you end up replacing an existing string by accident.

The most obvious way to solve this issue is to use a custom key, e.g.

public class MyKey {
  static private Random r = new Random();

  private String keyValue; 
  private final int hashCode = r.nextInt();

  @Override
  public int hashCode() {
    return hashCode;
  }

  public void setKeyValue(String keyValue) {
    this.keyValue = keyValue;
  }

  public String getKeyValue() {
    return keyValue;
  }
}

This key has a string key value which you can easily set / get and a hashCode which is just a random number. Once you add this key to the hash map you can change the string in situ without adding or removing the key. All you need do is iterate the key set and perform any processing you like on the key, all without affecting the hashcode or running the risk of collisions or anything else.

locka
+1 I overlooked the collision part (supposing that the OP knew what it would do) but you're right to specify it.
Colin Hebert
I am not sure this strategy would be convenient. You would need to always keep a reference to each specific MyKey instance because there is no way to recover the hashCode. But if you have to keep track of MyKey, why don't you just keep track of the value in the first place?
Barthelemy
Barthelemy, the issue as I see it that a key is meant to be an unique reference to data in a hashmap. if you change the key (such as by changing one string for another) then you run the risk of collisions and other unpleasantness. Therefore, the key should be something which is unique but provides access to a payload. The hashcode is just a hint for the hashmap. Strictly speaking it should be as unique as possible, but it's just used by the algorithm when choosing which bucket to stick the key in. It would typically be used in conjunction with equals().
locka
+2  A: 

Here's a solution that "deals with" collisions by throwing an exception.

public void replaceKeysChar(char originalChar, char newChar, Map<String, ?> map) {
    Map<String, Object> tempMap = new HashMap<String, Object>();
    Set<String> tempSet = new HashSet<String>();
    for (Map.Entry<String, ?> entry : map.entrySet()) {
        String originalKey = entry.getKey();
        String newKey = originalKey .replace(originalChar, newChar);
        if (!newKey.equals(originalKey)) {
            if (map.containsKey(newKey) || tempMap.containsKey(newKey)) {
                throw new CollisionException(newKey);
            }
            tempMap.put(newKey, entry.getValue());
            tempSet.add(originalKey());
        }
    }
    map.keySet().removeAll(tempSet);
    map.putAll(tempMap);
}

EDIT

Fixed bugs ... in previous versions.

Stephen C
How to use this method with my existing application code.
John
@John `replaceKeysChar('k', 'j', yourMap);`
Stephen C
@Stephen C, This method doesn't remove old keys (before the replace), and a `map.clear()` (to remove old keys) would also remove the keys that haven't changed.
Colin Hebert
@Colin - I spotted it before you did :-P . Fixed now.
Stephen C
@Stephen C, I find this method kind of "heavy" with the additional `Set`. Plus it won't handle `null` values (nor `null` keys [I just repaired that])
Colin Hebert
@Colin - it is more complicated, but assuming that you only rename a small percentage of the entries it should be significantly more efficient. Fixed the null value case. The null key case is impossible.
Stephen C
@Stephen C, HashMap allows a null key ;)
Colin Hebert
http://stackoverflow.com/questions/3855067/replace-all-keys-in-hashmap-starting-with-a-character Can u help me above on this
John
@Colin - ok, but in this context a null key would almost certainly be an application-level bug and hence letting it NPE would be better than trying to support it.
Stephen C