Sort list by multiple fields(not then compare) in java

Viewed 83

Now I have an object:

public class Room{
    private long roomId;
    private long roomGroupId;
    private String roomName;
    ... getter 
    ... setter
}

I want sort list of rooms by 'roomId', but in the meantime while room objects has 'roomGroupId' greator than zero and has same value then make them close to each other. Let me give you some example:

input:

[{"roomId":3,"roomGroupId":0},
 {"roomId":6,"roomGroupId":0},
 {"roomId":1,"roomGroupId":1},
 {"roomId":2,"roomGroupId":0},
 {"roomId":4,"roomGroupId":1}]

output:

[{"roomId":6,"roomGroupId":0},
 {"roomId":4,"roomGroupId":1},
 {"roomId":1,"roomGroupId":1},
 {"roomId":3,"roomGroupId":0},
 {"roomId":2,"roomGroupId":0}]

As shown above, the list sort by 'roomId', but 'roomId 4' and 'roomId 1' are close together, because they has the same roomGroupId.

2 Answers

This does not have easy nice solution (maybe I am wrong).

You can do this like this

        TreeMap<Long, List<Room>> roomMap = new TreeMap<>();

        rooms.stream()
             .collect(Collectors.groupingBy(Room::getRoomGroupId))
             .forEach((key, value) -> {
                 if (key.equals(0L)) {
                     value.forEach(room -> roomMap.put(room.getRoomId(), Arrays.asList(room)));
                 } else {
                     roomMap.put(
                         Collections.max(value, Comparator.comparing(Room::getRoomId))
                                    .getRoomId(),
                         value
                             .stream()
                             .sorted(Comparator.comparing(Room::getRoomId)
                                               .reversed())
                             .collect(Collectors.toList())
                     );
                 }
             });

        List<Room> result = roomMap.descendingMap()
                                   .entrySet()
                                   .stream()
                                   .flatMap(entry -> entry.getValue()
                                                          .stream())
                                   .collect(Collectors.toList());

If you're in Java 8, you can use code like this

Collections.sort(roomList, Comparator.comparing(Room::getRoomGroupId)
            .thenComparing(Room::getRoomId));

If not, you should use a comparator

class SortRoom implements Comparator<Room> 
{ 
 
    public int compare(Room a, Room b) 
    { 
        if (a.getRoomGroupId().compareTo(b.getRoomGroupId()) == 0) {
            return a.getRoomId().compareTo(b.getRoomId());
        }
            
        return a.getRoomGroupId().compareTo(b.getRoomGroupId(); 
    } 
} 

and then use it like this

Collections.sort(roomList, new SortRoom()); 
Related