Search code examples
javaguavamultimap

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.


Solution

  • 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());
            rangeSet.add(value);
            return rangeSet;
        }
    
        @Override
        public RangeSet<V> put(K key, RangeSet<V> value) {
            return map.put(key, value);
        }
    
        @Override
        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")));
    System.out.println(sensorIDsWithTimeRange);
    sensorIDsWithTimeRange.put(0, Range.closedOpen(valueOf("02:11:12"), valueOf("12:45:19")));
    System.out.println(sensorIDsWithTimeRange);
    

    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)]}