Defozo Defozo - 1 year ago 48
Java Question

Is there a way to have a map like ArrayListMultimap but with RangeSet and "coalescing" instead?

I want a map which assignes RangeSets to Integers in a way that instead of:

Map<Integer, RangeSet> sensorIDsWithTimeRange = new HashMap<>();
if (sensorIDsWithTimeRange.containsKey(sensorId)) {
sensorIDsWithTimeRange.get(sensorId).add(Range.closedOpen(startTime, endTime));
} else {
RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closedOpen(startTime, endTime));
sensorIDsWithTimeRange.put(sensorId, rangeSet);

I would write just:

sensorIDsWithTimeRange.put(sensorId, Range.closedOpen(startTime, endTime));

And it would create a new key if the key not already exists or insert new range to already existing RangeSet and coalescent it if the key exists.

Answer Source

You can use java.util.AbstractMap to quickly create your own custom Map type:

public class RangeSetHashMap<K, V extends Comparable> extends AbstractMap<K, RangeSet<V>> {
    private final Map<K, RangeSet<V>> map = new HashMap<>();

    public RangeSet<V> put(K key, Range<V> value) {
        RangeSet<V> rangeSet = computeIfAbsent(key, k -> TreeRangeSet.create());
        return rangeSet;

    public RangeSet<V> put(K key, RangeSet<V> value) {
        return map.put(key, value);

    public Set<Entry<K, RangeSet<V>>> entrySet() {
        return map.entrySet();

Example usage:

RangeSetHashMap<Integer, Time> sensorIDsWithTimeRange = new RangeSetHashMap<>();
sensorIDsWithTimeRange.put(0, Range.closedOpen(valueOf("12:30:00"), valueOf("12:40:00")));
sensorIDsWithTimeRange.put(0, Range.closedOpen(valueOf("17:09:42"), valueOf("23:06:33")));
sensorIDsWithTimeRange.put(1, Range.closedOpen(valueOf("04:13:56"), valueOf("04:14:02")));
sensorIDsWithTimeRange.put(0, Range.closedOpen(valueOf("02:11:12"), valueOf("12:45:19")));

Example output:

{0=[[12:30:00‥12:40:00), [17:09:42‥23:06:33)], 1=[[04:13:56‥04:14:02)]}
{0=[[02:11:12‥12:45:19), [17:09:42‥23:06:33)], 1=[[04:13:56‥04:14:02)]}