There are several ways to select top N objects from A list in the order of multiple data members of an object. For example, you may select top 10 players (top scores) from a list ordered by the players’ score_1, score_2 and then score_3.
The Simplest Way But Ineffective
The simplest way to pick the top N elements is to sort the whole list and get the top N elements. This method is easy to understand and implement but the overhead is too high. It might take a lot of memory or temporary disk resource if the list is big (especially if you need to load all the data from a file or you simple cannot use the normal SQL sorting method to sort the data) and it will takes lot of comparison during sorting. When the list size goes big, the side effect on performance becomes greater too.
The More Effective Way
The more effective way does not necessary always complicated. You can simply use the fixed-size PriorityQueue
in java.util
package to achieve the same result but with much better performance. PriorityQueue
is based on priority heap and the elements in PriorityQueue
are ordered according to their natural ordering.
PriorityQueue
provides O(log(n))
time for the enqueing and dequeing methods. To make the elements ordered in natural ordering, you need to make sure the element’s class implements the Comparable
interface or provide a appropriate Comparator
instance for the elements.
Below is an example on how to use PriorityQueue
to get Top N objects from a list (either loaded from file or database):
public class TopList { private T[] tlArray; private Comparator tlComparator; private PriorityQueue tlHeapSort; public TopList(T[] array, Comparator comparator) { tlArray = array; tlComparator = comparator; tlHeapSort = new PriorityQueue(array.length, comparator); } public void put(T item) { if (tlHeapSort.size() < tlArray.length) { tlHeapSort.add(item); } else if (tlComparator.compare(tlHeapSort.peek(), item) < 0) { tlHeapSort.poll(); tlHeapSort.add(item); } } public void finish() { int i; // Index for (i = tlHeapSort.size() - 1; i >=0 ; i--) { tlArray[i] = tlHeapSort.poll(); } } } public class Player { int score_1; int score_2; int score_3; String name; } public static void main (String args[]) { Comparator comparator; Player[] topPlayers; TopList topList; Player p; topPlayers = new Player[10]; comparator = new Comparator() { @Override public int compare(Player o1, Player o2) { int diff1, diff2, diff3; diff1 = o1.score_1 - o2.score_1; if (diff1 != 0) return diff1; diff2 = o1.score_2 - o2.score_2; if (diff2 != 0) return diff2; diff3 = o1.score_3 - o2.score_3; if (diff3 != 0) return diff3; return 0; } } topList = new TopList(topPlayers, comparator); // Load from files or database while (/* has records */) { p = /* Load a player instance */; topList.put(p); } topList.finish(); // Print the top winners System.out.printf ("TOP PLAYERS\n"); for (int i = 0; i < topPlayers.length; i++) { p = topPlayers[i]; if (p == null) break; System.out.printf ("%d %s (%d, %d, %d)\n", i + 1, p.name, p.score_1, p.score_2, p.score_3); } }
With this implementation, it will not burden your memory and CPU usage, even you have to select only 10 elements out of millions data.
Leave a Reply