This is a lot harder to read, but will perform a lot better:
public static List<String> firstN(Map<String, Integer> map, int n) {
PriorityQueue<Entry<String, Integer>> pq = new PriorityQueue<>(
n + 1, Map.Entry.comparingByValue()
);
int bound = n + 1;
for (Entry<String, Integer> en : map.entrySet()) {
pq.offer(en);
if (pq.size() == bound) {
pq.poll();
}
}
int i = n;
String[] array = new String[n];
while (--i >= 0) {
array[i] = pq.remove().getKey();
}
return Arrays.asList(array);
}
If you know how a PriorityQueue
works, this is rather trivial: it keeps only n + 1
elements at any given point in time. As elements are being added, the smallest element is removed, one by one.
When this is done, we insert elements into an array, but in reverse order (because a PriorityQueue
keeps sorted only its head or the head is always max/min according to the Comparator
).
You can even make this generic, or create a custom collector with streams for this.