Wednesday, January 20, 2016

Removing multiple items from a JavaScript array, no for loops

So I was reviewing some code today that was using two for loops to remove elements from a JavaScript array, I won't relate the code here but I figured there as got to be a nicer way. So the first guess is to make use of the filter method; but that creates a new array which might be problem if the array is large but not if it is fairly small or not called very often.

providers = providers.filter(function(provider) {
     return provider.age > 35
}

For performance or API reasons you might want to perform an in place removal using splice, so you can simple map the values to indexes you want to remove, reverse the order then perform a sequence of splice operations:

providers.map(function(provider, index) {
    return provider.age > 35 ? index : -1;
}).filter(function(index) {
    return index >= 0;
}).reverse().forEach(function(index) {
    providers.splice(index,1);
});

You can play with this code in this jsfiddle.

Update 21 Jan 20125: The hazard of doing full stack development is that it is easy to accidentally duck type between languages whilst forgetting the impact. In Java the equivalent streaming code using map just returns another lazy step in the stream whereas in JavaScript you end up creating a new array of the same size as the original. This removes the performance improvement over the first example if you have lots of data. This is simple too fix though as you can use the reduce function to just create an array and populate it using the reduce operation:

providers.reduce(function(list, provider, index) {
    if (provider.age> 35) list.push(index);
    return list;
}, []).reverse().forEach(function(index) {
    providers.splice(index,1);
});

Here is the updated fiddle. I guess at some point I am going to have to benchmark these variants to see which is best; but that is for a less busy day.

Tuesday, January 12, 2016

Beware of slightly different behaviour between ConcurrentMap and ConcurrentHashMap for computeIfAbsent

So I was refactoring some code to use non-locking collection classes and I noticed the this significant different between ConcurrentMap.computeIfAbsent and ConcurrentHashMap.computeIfAbsent. They key different is that for the former default implementing the mapping function can be called many times for a particular key where as for the concrete implementation it will be called only once. This will likely affect whether the code in the function needs to be thread safe or not.

Right okay so armed with that you know that any collection that implements just ConcurrentMap will inherit this behaviour, further to that I found in particular guava would return a different implementation depending on the passed on parameters:

ConcurrentMap map1 = new MapMaker().makeMap();
System.out.println(map1.getClass());

ConcurrentMap map2 = new MapMaker().weakKeys().makeMap();
System.out.println(map2.getClass());

....

class java.util.concurrent.ConcurrentHashMap
class com.google.common.collect.MapMakerInternalMap

MapMakerInternalMap doesn't override computerIfAbsent therefore the behaviour of this function will be significantly different depending on the parameters to pass into the maker, something that might be apparent from the get go.