我需要根据多键找到一些非常快的值。
关键是由:
< Int userId, String measureName, Date startDate, Date endDate >
而且价值是双倍的。
问题是我必须要求指示一天的值,而不是日期范围。
因此,如果我要求userId
,measureName
和一天,则数据结构必须回答日期介于startDate
和endDate
之间的值(日期范围之间没有重叠。)
我无法理解哪个是更好的数据结构来实现它。 HashMap类? TreeMap的? MultiKeyMap? RangeMap?救命! :)
答案 0 :(得分:3)
我认为你应该使用TreeMap和方法: http://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html#floorEntry(K) http://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html#higherEntry(K) 但在比较函数中只使用一个日期 - startDate或endDate。由于这些范围不重叠,因此这不应成为问题,并使TreeMap中提到的方法可用。
例如:如果您决定使用比较endDate
(以及除其他日期以外的其他字段),则应使用方法floorEntry
答案 1 :(得分:0)
使用自定义键对象的TreeMap最好。你有类似的东西:
...
TreeMap<MyMultiKey,Double> map = ...
class MyMultiKey implements Comparable<MyMultiKey>{
...
}
假设已实施MyMultiKey
的{{1}}方法来正确订购您的多个密钥,您可以在每次要使用特定日期搜索时创建新的compareTo
实例MyMultiKey
和map.floorKey(MyMultiKey m)
以确保找到包含您在新密钥实例中指定日期的开始和结束时间的密钥。
答案 2 :(得分:0)
我建议用户/测量部分键的一些Map。 该值将是元组的排序数组(日期范围,floatval)。 在此数组中,您可以对包含日期的日期范围执行二进制搜索。
答案 3 :(得分:0)
Map
和有序List
的组合怎么样?地图的复合键为userId
和measureName
,该值是日期范围的排序列表,并且加倍value
:
Map<Key,List<Entry>> data = new HashMap<>();
List<Entry> entries = data.get(new Key(userId, measureName));
int i = Collections.binarySearch(entries, new Entry(searchDate,searchDate, 0.0));
double value = i < 0 ? 0.0 : entries.get(i).value;
Key
必须使用其成员hashCode()
和equals()
来实施userId
和measureName
。 Entry
必须实现Comparable<Entry>
,其中compareTo()
必须返回0,如果一个范围是另一个范围的一部分(startDate比较是&lt; = 0并且endDate比较是&gt; = 0或0,如果startDate比较是&gt; = 0并且endDate比较是&lt; = 0)否则比较startDate +(endDate-startDate)/ 2(范围的中间),而不管双value
。
如果你主要阅读而不是修改这个结构,它应该很快。如果使用太多,比较将编译为本机。如果该函数仅适用于单个用户并仅进行度量,则只能使用排序列表,如果仅使用单个用户,则可以创建Map<UserId<Map<MeasureName,List<Entry>>>>
类似结构。
首先尝试一个简单的解决方案,在之前和之后进行测量,仅在需要时进行性能优化。