Remove map keys by prefix

apexmapprefix

Is there an efficient way to remove all map records that start with a specific prefix?
For example:

Map<String, Account> accMap = new MapMap <String, Account>();
accMap.put('Mr.A', new account());
accMap.put('Mr.B', new account());
accMap.put('Miss.B', new account());

and I want to remove the first 2 records from the map.
Should I run a for loop and check every key's prefix?

Best Answer

Salesforce does not provide us with a method to remove keys from a Map based on prefixes. The map type uses hashing to store keys in the data structure behind-the-scenes, which means any prefix would have a completely unrelated hash.

Unless you already have a set of map keys that you want to remove, I imagine that you would need to iterate over every map key.

As a simple example

Set<String> keysToRemove = new Set<String>();
String prefix = 'foo';

for(String key : myMap.keySet()){
    if(key.startsWith(prefix)){
        keysToRemove.add(key);
    }
}

myMap.keySet().removeAll(keysToRemove);

edit: simple benchmark

Because I got a little curious, I did run some simple tests on the set + keySet().removeAll() approach vs just calling map's remove() method in the loop.

Here's the code I used to benchmark:

Map<String, Integer> testMap = new Map<String, Integer>();

for(Integer i = 0; i < 100000; i++){
    testMap.put(String.valueOf(i), 0);
}

String prefix = '100';

Long startTime, endTime, emptyLoopTime;

startTime = System.now().getTime();

for(String key :testMap.keySet()){
    
}

endTime = System.now().getTime();
emptyLoopTime = endTime - startTime;

// One of these will always be commented out
/*startTime = System.now().getTime();

for(String key :testMap.keySet()){
    if(key.startsWith(prefix)){
        testMap.remove(key);
    }
}

endTime = System.now().getTime();
*/
startTime = System.now().getTime();

Set<String> keysToRemove = new Set<String>();
for(String key :testMap.keySet()){
    if(key.startsWith(prefix)){
        keysToRemove.add(key);
    }
}

testMap.keySet().removeAll(keysToRemove);

endTime = System.now().getTime();

system.debug(endTime - startTime - emptyLoopTime);

The first run was simply to warm up Salesforce's apex cache. After that, I performed 5 runs for each approach.

With a map of 100k size, I measured that it took

  • 576.6 ms of real time, 2189 cpu time for the keySet().removeAll() approach
  • 593.4 ms of real time, 2052 cpu time for the .remove() in the loop approach

The varience in measured times for both approaches makes the difference insignificant, and that's even before you consider that this was done on a map of size 100k.

In real usage, there will be no measurable difference.

Related Topic