假设您从“流”源读取数据项和相关分数(即无法随机访问或多次传递)。
在任何时候,只保留目前遇到的最低权重的内存元素的最佳方法是什么。我会对“Java”方式感兴趣,成语越短越好,而不是算法(“使用搜索树,插入新元素,如果超出大小则删除最大”)。
下面是我提出的解决方案,但是我发现它有点冗长,也有一些行为可能是意外的(具有不同分数的相同项目可能会保留多次,同时保留相同的项目添加相同的分数只有一次)。我也觉得应该有一些东西存在。
import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import java.util.Comparator;
import java.util.TreeSet;
/**
* Stores the n smallest (by score) elements only.
*/
public class TopN<T extends Comparable<T>> {
private TreeSet<Entry<T, Double>> elements;
private int n;
public TopN(int n) {
this.n = n;
this.elements = new TreeSet<Entry<T, Double>>(
new Comparator<Entry<T, Double>>() {
@Override
public int compare(Entry<T, Double> o1, Entry<T, Double> o2) {
if (o1.getValue() > o2.getValue()) return 1;
if (o1.getValue() < o2.getValue()) return -1;
return o1.getKey() == null ? 1 : o1.getKey().compareTo(o2.getKey());
}
});
}
/**
* Adds the element if the score is lower than the n-th smallest score.
*/
public void add(T element, double score) {
Entry<T, Double> keyVal = new SimpleEntry<T, Double>(element,score);
elements.add(keyVal);
if (elements.size() > n) {
elements.pollLast();
}
}
/**
* Returns the elements with n smallest scores.
*/
public TreeSet<Entry<T, Double>> get() {
return elements;
}
}
有一个类似的问题,但它不包括流源/内存要求: Find top N elements in an Array
答案 0 :(得分:5)
使用“堆”数据结构。 Java有一个内置的:PriorityQueue
。只需将比较器定义为“最佳”,然后将流中的所有数据提供给优先级队列。
编辑:
要为此答案添加更多颜色,您可能需要执行以下操作:
Collections.reverseOrder(...)
poll()
从堆中删除“top”元素 - 由于您的比较器,它实际上将是“最差”的元素你剩下的是一个有n个元素的pqueue,其中“最不好”。
答案 1 :(得分:1)
你可以通过番石榴的Comparators
课来获得理想的结果。请参阅下面的示例,该示例获得前5个数字。可以找到Api here。
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collector;
import org.junit.Test;
import com.google.common.collect.Comparators;
import com.google.common.collect.Lists;
public class TestComparator {
@Test
public void testTopN() {
final List<Integer> numbers = Lists.newArrayList(1, 3, 8, 2, 6, 4, 7, 5, 9, 0);
final Collector<Integer, ?, List<Integer>> collector = Comparators.greatest(5,
Comparator.<Integer>naturalOrder());
final List<Integer> top = numbers.stream().collect(collector);
System.out.println(top);
}
}
输出:[9,8,7,6,5]