Home > front end >  How to get all entries with second highest value of a Hashmap?
How to get all entries with second highest value of a Hashmap?

Time:12-14

I want to get the second max number or value of a Map by using Java Streams.

If multiple values are present then also I want both key and value.

HashMap<String, Integer> map = new HashMap<String,Integer>();       
    map.put("Pankaj",1);
    map.put("Amit",2);
    map.put("Rahul",5);
    map.put("Chetan",7);
    map.put("Vinod",6);
    map.put("Amit",8);
    map.put("Rajesh", 7);
        
Entry<String, Integer> m = map.entrySet().stream()
    .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
    .skip(1)
    .findFirst()
    .get();

CodePudding user response:

To get the second maximum value from a Map using Java Streams, you can use the sorted() and skip() methods to sort the values in the Map in descending order and then skip the first value.

The code would look something like this:

Map<Integer, Integer> map = new HashMap<>();

// Add some key-value pairs to the map
map.put(1, 4);
map.put(2, 3);
map.put(3, 5);
map.put(4, 1);

// Get the second maximum value using Streams
int secondMax = map.values().stream()
    .sorted(Collections.reverseOrder())
    .skip(1)
    .findFirst()
    .orElse(null);

// Print the second maximum value
System.out.println(secondMax); // Output: 4

First, create a Map and add some key-value pairs to it. Then, use the values() method to get a stream of the values in the map, and use the sorted() method to sort the values in descending order. We then use the skip(1) method to skip the first value, and use the findFirst() method to get the first element in the stream. Finally, use the orElse() method to specify a default value to return if the stream is empty.

This code will output the second maximum value from the Map, which is in this case: 4.

But in your case, you can do this:

Map<Integer, Integer> map = new HashMap<>();

// Add some key-value pairs to the map
map.put(1, 4);
map.put(2, 3);
map.put(3, 5);
map.put(4, 1);
map.put(5, 4);

// Get the second maximum value using Streams
Map.Entry<Integer, Integer> secondMax = map.entrySet().stream()
    .sorted(Map.Entry.comparingByValue(Collections.reverseOrder()))
    .skip(1)
    .findFirst()
    .orElse(null);

// Print the second maximum value and corresponding key
System.out.println(secondMax.getKey()   ": "   secondMax.getValue()); // Output: 5: 4

This code will output the second maximum value and the corresponding key from the Map, which is 5 and 4 in this case. Note that if there are multiple entries with the same maximum value, this code will return the first entry with that value, along with its corresponding key.

CodePudding user response:

I would collect the map into a TreeMap sorted by the keys in reverse order using groupingBy. Then get the 2nd element from it using skip as,

TreeMap<Integer, List<String>> treeMap = map.entrySet()
            .stream()
            .collect(Collectors.groupingBy(Map.Entry::getValue,
                    () -> new TreeMap<>(Comparator.<Integer>reverseOrder()),
                    Collectors.mapping(Map.Entry::getKey, Collectors.toList())));

Map.Entry<Integer, List<String>> result = treeMap.entrySet()
            .stream()
            .skip(1)
            .findFirst()
            .get();
System.out.println(result);

Outputs,

7=[Rajesh, Chetan]

Note, we are assuming a second-max will always be present as we call get on an Optional.

CodePudding user response:

Be simple! The key word is a second max. It means you should use PriorityQueue:

Queue<Map.Entry<String, Integer>> maxQueue = new PriorityQueue<>((one, two) ->
                              Integer.compare(two.getValue(), one.getValue()));
maxQueue.addAll(map.entrySet());

Map.Entry<String, Integer> firstMax = maxQueue.remove();
Map.Entry<String, Integer> secondMax = maxQueue.remove();

CodePudding user response:

If multiple values are present then also I want both key and value.

Your code works only for a single value. In order to get the multiple values, group the entries on their values and then apply your code on the Stream derived from the resulting Map.

Demo:

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

class Main {

    public static void main(String args[]) {
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        map.put("Pankaj", 1);
        map.put("Amit", 2);
        map.put("Rahul", 5);
        map.put("Chetan", 7);
        map.put("Vinod", 6);
        map.put("Amit", 8);
        map.put("Rajesh", 7);

        List<Entry<String, Integer>> result = map.entrySet()
                .stream()
                .collect(Collectors.groupingBy(e -> e.getValue()))
                .entrySet()
                .stream()
                .sorted(Collections.reverseOrder(Map.Entry.comparingByKey()))
                .skip(1)
                .findFirst()
                .get()
                .getValue();

        System.out.println(result);
    }
}

Output:

[Rajesh=7, Chetan=7]
  • Related