I need to find the topN keys.
I have an input as a HashMap in the form as (key : value):
Banana : 13
Apple: 12
Mango : 32
Orange : 12
Grape : 18
Pear : 12
Peach : 18
I created a linked HapMap that is sorted based on values:
private static <K extends Comparable, V extends Comparable> Map<K, V> sortByValues(Map<K, V> map) {
List<Map.Entry<K, V>> entries = new LinkedList<Map.Entry<K, V>>(map.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<K, V>>() {
@Override
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
Map<K, V> sortedMap = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : entries) {
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
this gave my the output as:
Mango : 32
Grape : 18
Peach : 18
Banana : 13
Apple: 12
Orange : 12
Pear : 12
Now if I want to the Top-4 fruits, how should I approach if I want the output to be:
Mango :32
Grape, Peach : 18
Banana :13
Apple, Orange, Pear: 12
I tried iterating through the sorted hashMap and compared the values of subsequent elements by doing
int sizeOfMap = myValueSortedMap.size();
ArrayList<String> keyArr = new ArrayList<String>();
int cnt=0,keyVal=0;
while(cnt<(sizeOfMap-1)){
if(myValueSortedMap.values().toArray()[cnt] == myValueSortedMap.values().toArray()[cnt+1]){
keyArr.add((String) myValueSortedMap.keySet().toArray()[cnt]+ " , " +(String) myValueSortedMap.keySet().toArray()[cnt+1]);
}
else{
keyArr.add((String) myValueSortedMap.keySet().toArray()[cnt]);
keyVal = (int) myValueSortedMap.values().toArray()[cnt];
}
cnt++;
}
but this does not always work.
I am not able to think of a way around this. Could someone please give me a lead?
You can use a two-step stream process - the first step groups the entries by the numeric value, the second sorts the stream contents, applies the limit of 4 and prints the result.
map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue))
// the map now contains integers mapped to a list of map entries
.entrySet()
.stream()
// sort the stream by descending numeric value
.sorted((o1, o2) -> o2.getKey().compareTo(o1.getKey()))
// use the first four elements of the stream
.limit(4)
.forEach(entry -> System.out.println(entry.getKey() + " " + entry.getValue().stream().map(Map.Entry::getKey).collect(Collectors.joining(", "))));
This results in
32 Mango
18 Grape, Peach
13 Banana
12 Apple, Pear, Orange
As I said in my comment, you will need to reverse your map first : so Map<String, Integer>
will become Map<Integer, List<String>>
.
Then, you can retrieve 4 max keys from your new map (formerly the values of your first map) and print their values
public static <K extends Comparable, V extends Comparable> Map<V, List<K>> reverseMap(Map<K, V> map) {
Map<V, List<K>> result = new HashMap<>();
map.entrySet().stream().forEach((entry) -> {
List<K> lst = result.get(entry.getValue());
if (lst == null) {
lst = new ArrayList<>();
result.put(entry.getValue(), lst);
}
lst.add(entry.getKey());
});
return result;
}
Map<String, Integer> map = new HashMap<>();
map.put("Banana", 13);
map.put("Apple", 12);
map.put("Mango", 32);
map.put("Orange", 12);
map.put("Grape", 18);
map.put("Pear", 12);
map.put("Peach", 18);
Map<Integer, List<String>> flip = reverseMap(map);
flip.entrySet().stream()
.sorted(Map.Entry.<Integer, List<String>>comparingByKey().reversed())
.limit(4)
.forEach(e -> System.out.println(String.join(", ", e.getValue()) + " : " + e.getKey()));
Mango : 32
Grape, Peach : 18
Banana : 13
Apple, Pear, Orange : 12
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With