Data structures that can map a range of keys to a value

Are your ranges non-overlapping? If so you could use a TreeMap:

TreeMap<Double, Character> m = new TreeMap<Double, Character>();
m.put(1.0, 'A');
m.put(2.9, null);
m.put(4.0, 'B');
m.put(6.0, null);
m.put(6.5, 'C');
m.put(10.0, null);

The lookup logic is a bit complicated by the fact that you probably want an inclusive lookup (i.e. 2.9 maps to 'A', and not undefined):

private static <K, V> V mappedValue(TreeMap<K, V> map, K key) {
    Entry<K, V> e = map.floorEntry(key);
    if (e != null && e.getValue() == null) {
        e = map.lowerEntry(key);
    }
    return e == null ? null : e.getValue();
}

Example:

mappedValue(m, 5) == 'B'

More results include:

0.9 null
1.0 A
1.1 A
2.8 A
2.9 A
3.0 null
6.4 null
6.5 C
6.6 C
9.9 C
10.0 C
10.1 null

Guava RangeMap provides specialized solution out of the box:

RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 100), "foo"); // {[1, 100] => "foo"}
rangeMap.put(Range.open(3, 6), "bar"); // {[1, 3] => "foo", (3, 6) => "bar", [6, 100] => "foo"}

rangeMap.get(42); // returns "foo"

A HashMap will not work for mapping ranges to values unless you find a way to generate a hashcode for ranges and single values in there that matches. But below approach could be what you are looking for

public class RangeMap {
    static class RangeEntry {
        private final double lower;
        private final double upper;
        private final Object value;
        public RangeEntry(double lower, double upper, Object mappedValue) {
            this.lower = lower;
            this.upper = upper;
            this.value = mappedValue;
        }
        public boolean matches(double value) {
            return value >= lower && value <= upper;
        }
        public Object getValue() { return value; }
    }

    private final List<RangeEntry> entries = new ArrayList<RangeEntry>();
    public void put(double lower, double upper, Object mappedValue) {
        entries.add(new RangeEntry(lower, upper, mappedValue));
    }
    public Object getValueFor(double key) {
        for (RangeEntry entry : entries) {
            if (entry.matches(key))
                return entry.getValue();
        }
        return null;
    }
}

You could do

RangeMap map = new RangeMap();
map.put(1, 2.9, "A");
map.put(4, 6, "B");

map.getValueFor(1.5); // = "A"
map.getValueFor(3.5); // = null

It's not very efficient since it's just iterating over a list and it will in that state not complain if you put conflicting ranges in there. Will just return the first it finds.

P.S.: mapping like this would be mapping a range of keys to a value