TreeMap过滤了视图性能

时间:2014-08-29 17:50:24

标签: java performance treemap

我有一个课程(其中包括):

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%。由于该程序运行了数百万次模拟,这意味着在该方法中花费了数小时。

我怎样才能提高该方法的性能?

2 个答案:

答案 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
}
相关问题