我有一个课程(其中包括):
public class TimeSeries {
private final NavigableMap<LocalDate, Double> prices;
public TimeSeries() { prices = new TreeMap<>(); }
private TimeSeries(NavigableMap<LocalDate, Double> prices) {
this.prices = prices;
}
public void add(LocalDate date, double price) { prices.put(date, price); }
public Set<LocalDate> dates() { return prices.keySet(); }
//the 2 methods below are examples of why I need a TreeMap
public double lastPriceAt(LocalDate date) {
Map.Entry<LocalDate, Double> price = prices.floorEntry(date);
return price.getValue(); //after some null checks
}
public TimeSeries between(LocalDate from, LocalDate to) {
return new TimeSeries(this.prices.subMap(from, true, to, true));
}
}
现在我需要在地图上有一个“过滤”的视图,其中只有一些日期可用。为此,我添加了以下方法:
public TimeSeries onDates(Set<LocalDate> retainDates) {
TimeSeries filtered = new TimeSeries(new TreeMap<> (this.prices));
filtered.dates().retainAll(retainDates);
return filtered;
}
onDates
方法是一个巨大的性能瓶颈,占该程序处理时间的85%。由于该程序运行了数百万次模拟,这意味着在该方法中花费了数小时。
我怎样才能提高该方法的性能?
答案 0 :(得分:1)
最简单的优化:
public TimeSeries onDates(Set<LocalDate> retainDates) {
TreeMap<LocalDate, Double> filteredPrices = new TreeMap<>();
for (Entry<LocalDate, Double> entry : prices.entrySet() ) {
if (retainDates.contains( entry.getKey() ) ) {
filteredPrices.put( entry.getKey(), entry.getValue() );
}
}
TimeSeries filtered = new TimeSeries( filteredPrices );
return filtered;
}
首先为您节省制作地图完整副本的费用,然后再次遍历该副本进行过滤。
答案 1 :(得分:1)
我试试ImmutableSortedMap
,假设您可以使用它。它基于排序数组而不是平衡树,所以我猜它的开销要小得多(*)。为了构建它,你需要采用biziclop的想法,因为构建器不支持删除。
(*)那里有一个Collection.sort
的调用,但它应该是无害的,因为集合已经被排序并且TimSort
针对这种情况进行了优化。
如果在创建onDates
后您的原始地图未发生变化,则视图可能有所帮助。万一它,你需要一些“持久”的地图,听起来相当复杂。
也许基于排序数组和二进制搜索的一些hacky解决方案可能是最快的,也许你甚至可以先将LocalDate
转换为int
然后转换为double
并将所有内容放入单个交错中double[]
以节省内存(希望也是时间)。你需要自己的二分搜索,但这很简单。
视图的想法很简单,假设
NavigableMap
方法,只需要几种方法retainDates
示例方法:
public double lastPriceAt(LocalDate date) {
Map.Entry<LocalDate, Double> price = prices.floorEntry(date);
while (!retainDates.contains(price.getKey()) {
price = prices.lowerEntry(price.getKey()); // after some null checks
}
return price.getValue(); // after some null checks
}