daisy
daisy

Reputation: 357

Get all Top N rank records in java

i have a HashMap resultdata like below

"zip000", 1234
"zip001", 2345
"zip002", 3456
"zip003", 4567
"zip004", 7890
"zip005", 7890
"zip006", 123
"zip007", 234
"zip010", 7890
"zip011", 678
"zip012", 789
"zip013", 890

and used below code

  public static List<String> topNKeys(final HashMap<String, Integer> map, int n) {
    PriorityQueue<String> topN = new PriorityQueue<String>(n, new Comparator<String>() {
        public int compare(String s1, String s2) {
            return Integer.compare(map.get(s1), map.get(s2));
        }
    });

    for(String key:map.keySet()){
        if (topN.size() < n)
            topN.add(key);
        else if (map.get(topN.peek()) < map.get(key)) {
            topN.poll();
            topN.add(key);
        }
    }
    return (List) Arrays.asList(topN.toArray());
}

Above code displays me topN records as

Assume n= 6

zip001=2345
zip002=3456
zip003=4567
zip005=7890
zip010=7890
zip004=7890

But i need it to give all top 6 resultdata according to Integer Rank, i mean like below

zip013=890
zip000=1234
zip001=2345
zip002=3456
zip003=4567
zip005=7890
zip010=7890
zip004=7890

According to integers where 7890,4567,3456,2345,1234,890 are the top 5 Integers.

How could i do this? Any kind of help and suggestion is appreciated.

Upvotes: 0

Views: 796

Answers (1)

assylias
assylias

Reputation: 328835

You could do it in two steps:

  1. gather the distinct top N numbers
  2. collect all the entries that have a value in the top N

In terms of code, you could write it like this:

public static List<Entry<String, Integer>> topNKeys(Map<String, Integer> map, int n) {
  Set<Integer> topValues = getTopValues(map, n);
  return getEntriesWithTopValues(map, topValues);
}

//Returns the distinct top n values
private static Set<Integer> getTopValues(Map<String, Integer> map, int n) {
  TreeSet<Integer> values = new TreeSet<>(map.values());
  Set<Integer> topNValues = new HashSet<>();
  for (int i = 0; i < n; i++) {
    Integer v = values.pollLast();
    if (v != null) topNValues.add(v);
    else break;
  }
  return topNValues;
}

//Returns the entries with a value that is contained in topValues
private static List<Entry<String, Integer>> getEntriesWithTopValues(Map<String, Integer> map, Set<Integer> topValues) {
  return map.entrySet().stream()
          .filter(e -> topValues.contains(e.getValue()))
          .sorted(Entry.comparingByValue())
          .collect(toList());
}

Applied to your example, it returns the desired output.

Without stream, the last method could be written:

private static List<Entry<String, Integer>> getEntriesWithTopValues(Map<String, Integer> map, Set<Integer> topValues) {
  List<Entry<String, Integer>> result = new ArrayList<> ();
  for (Entry<String, Integer> e : map.entrySet()) {
    if (topValues.contains(e.getValue())) result.add(e);
  }

  Collections.sort(result, new Comparator<Entry<String, Integer>>() {
    @Override
    public int compare(Entry<String, Integer> e1, Entry<String, Integer> e2) {
      return e1.getValue().compareTo(e2.getValue());
    }
  });

  return result;
}

Upvotes: 2

Related Questions