Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort HashMap entries values by multiple properties Java8 [duplicate]

Tags:

java

java-8

How sort HashMap entries by multiple properties.

Suppose I have a map with key String and value as Object.

Map<String, UserMetrics> map = new HashMap<>
map.put("user10",new UserMetrics(1,100,111));
map.put("user3",new UserMetrics(10,330,444));
map.put("user11",new UserMetrics(333,100,555));
map.put("user1",new UserMetrics(1,111,433));

 public static class UsageMetrics implements Serializable {
        private long param1;
        private long param2;
        private long param3;....
 }

I want to sort users first by "param1" and then after by "param2"

result expected:<>

user10, UserMetrics(1,100,111)
user1,  UserMetrics(1,111,433))
user3,  UserMetrics(10,330,444));
user11, UserMetrics(333,100,555))
like image 205
VitalyT Avatar asked Apr 12 '18 08:04

VitalyT


2 Answers

You can use the following comparator for sorting:

Comparator
        .comparingLong(UserMetrics::getParam1)
        .thenComparingLong(UserMetrics::getParam2);

The difficulty is, however that you want to sort values, not keys. It seems also you need both keys and values. For this you could make and sort a copy of the entry set of your map. Something along the lines:

List<Map.Entry<String, UserMetrics>> sortedEntries = new ArrayList<>(map.entrySet());
Collections.sort(sortedEntries,
    Map.Entry.comparingByValue(
        Comparator
            .comparingLong(UserMetrics::getParam1)
            .thenComparingLong(UserMetrics::getParam2)));

Alternatively you can also use a sorted collection (like TreeSet) or a sorted stream - normally you can provide your own comparator to the "sorting things".

Also note that I'm using comparingLong/thenComparingLong, unlike other answers where people just used comparing/thenComparing. The problem with comparing/thenComparing is that if you have primitive types like long, comparing/thenComparing will essentially box them into wrapper types like Long, which is totally unnecessary.

like image 179
lexicore Avatar answered Nov 14 '22 23:11

lexicore


You can use below code. I have written by using Employee the s value object, so you can use your own Object :

public class Main {
    public static void main(String[] args) throws InterruptedException {
        HashMap<String, Employee> map = new HashMap<>();
        Map<String, Employee> sortedMap = map.entrySet()
                                             .stream()
                                             .sorted(Entry.comparingByValue(Main::compare))
                                             .collect(Collectors.toMap(Entry::getKey, Entry::getValue,
                                                     (e1, e2) -> e1, LinkedHashMap::new));

    }

    public static int compare(Employee e1, Employee e2) {
        return e1.getAge() - e2.getAge();
    }
}

Edited: Here is another way you can use Comparator#comparing and thenComparing to sort.

Map<String, Employee> sortedMap = map.entrySet()
                                     .stream()
                                     .sorted(Entry.comparingByValue(
                                             Comparator.comparing(Employee::getAge)
                                                       .thenComparing(Employee::getSalary)))
                                     .collect(Collectors.toMap(Entry::getKey, Entry::getValue,
                                             (e1, e2) -> e1, LinkedHashMap::new));
like image 36
Amit Bera Avatar answered Nov 14 '22 23:11

Amit Bera