1. Use a sorted, random-access data structure. A vector will suffice.
Store your data in this. This is good if your data doesn't change much.
Find the extremes of a range by binary search and linear walking. If
that's too slow, build a metaindex, which is simply a precalculated
binary search to a certain depth.
A lookup is then the computation of two indices. Your values lie
between those indices.
2. Store your values in a tree. Each node stores the range it
contains. Navigate the tree appropriately to find matching values.
This will take more space than the array.
Would it be possible to use a hash-map with the prices as the keys and vectors of items as your values? That way you get efficient access to your values if you know the price and aren't paying for the empty space.
That's one of the things sorted maps are for:
(let [objects-by-price (sorted-map 0.50 :cookie, 5.0 :lunch,
6.10 :movie, 200.0 :tv)]
(take-while #(<= (key %) 6.12) (subseq objects-by-price >= 3.27)))
=> ([5.0 :lunch] [6.1 :movie])
>> The naive way would be to make an
>> array with one slot for each increment in the entire range, and have
>> each slot pointing to a bucket with all items at that increment (here,
>> price). But this would not be terribly efficient or feasible over
>> very large ranges
Also, if you're wondering how sorted-map makes that fast, see:
http://en.wikipedia.org/wiki/Binary_search_tree
It just does a search and then traverses the tree from that point, so it
takes O((log n) + m) time where n is the size of the tree and m is the
number of items your query returns.
Richard's suggestion of binary search in a sorted array is also a good
option but is a bit of a pain if you need to add new items to the array.
I think what you are after is an interval tree[1] data structure. You
might find a suitable Java library or implement yours easily.
Regards.