【发布时间】:2015-03-31 07:46:39
【问题描述】:
我正在寻找一种在 Java 中节省内存的方法来从庞大的集合中查找前 n 个元素。例如,我有一个单词、一个 distance() 方法和一个“所有”单词的集合。 我已经实现了一个实现 compareTo() 的类 Pair,以便对按它们的值排序。
使用流,我的幼稚解决方案如下所示:
double distance(String word1, String word2){
...
}
Collection<String> words = ...;
String word = "...";
words.stream()
.map(w -> new Pair<String, Double>(w, distance(word, w)))
.sorted()
.limit(n);
据我了解,这将处理并以单词形式存储每个元素,以便在应用 limit() 之前对其进行排序。但是,拥有一个存储 n 个元素的集合更节省内存,并且每当添加一个新元素时,它都会删除最小的元素(根据可比较对象的自然顺序),因此永远不会增长大于 n(或 n+1 )。
这正是 Guava MinMaxPriorityQueue 所做的。因此,我目前对上述问题的最佳解决方案是:
Queue<Pair<String, Double>> neighbours = MinMaxPriorityQueue.maximumSize(n).create();
words.stream()
.forEach(w -> neighbours.add(new Pair<String, Double>(w, distance(word, w)));
将队列转换为流或列表后,前n个元素的排序仍有待完成,但这不是问题,因为n相对较小。
我的问题是:有没有办法使用流来做同样的事情?
【问题讨论】:
-
这根本不是
MinMaxPriorityQueue的重点:MinMaxPriorityQueue的唯一重点是当您实际上需要一个双端优先级队列来访问最大和最低元素时,确实如此这里似乎不是这样。maximumSize方面不是数据结构的重点,这将严重低效。 Guava 的Ordering.greatestOf函数针对这个确切的用例进行了严格优化,并且需要 O(n) 时间而不是 O(n log n)。 -
(Guava 的未来版本将有一个
Ordering.greatestOf版本,专门设计用于匹配 Java 8 Collector API。) -
感谢指点!我看不到使用 Ordering.greatestOf() 而不先将所有元素中间存储在集合中的方法,有吗?或者这只会在你提到的未来版本中才有可能?
-
不需要是集合,可以是
Iterable或Iterator。如果你有一个流,你可以做Ordering.natural().greatestOf(stream.iterator(), k)。 -
@LouisWasserman,你在番石榴的未来版本中说过。您是否也可以链接任何票证以便我们跟踪进度?我想我正在寻找类似
.stream().collect(myOrdering.greatestOfCollector(5))的东西。
标签: java sorting java-8 guava java-stream