Consider the dto class below -
public class RoleDto {
private String name;
RoleDto(String name) {
this.name = name;
}
}
Its instances would contain names like -
Business Practitioner - Expert
Developer - Expert
Developer - Master
Business Practitioner - Master
Business Practitioner
Developer
Developer - Professional
Business Practitioner - Professional
I want to sort the instances such that the order is -
Business Practitioner - Expert
Business Practitioner - Master
Business Practitioner - Professional
Business Practitioner
Developer - Expert
Developer - Master
Developer - Professional
Developer
I have used the code below -
ArrayList<RoleDto> roles = new ArrayList<>();
roles.add(new RoleDto("Business Practitioner - Expert"));
roles.add(new RoleDto("Developer - Expert"));
roles.add(new RoleDto("Developer - Master"));
roles.add(new RoleDto("Business Practitioner - Master"));
roles.add(new RoleDto("Business Practitioner"));
roles.add(new RoleDto("Developer"));
roles.add(new RoleDto("Developer - Professional"));
roles.add(new RoleDto("Business Practitioner - Professional"));
List<RoleDto> sorted = roles.stream().sorted(comparing(r -> r.getName(),
comparing((String s) -> !s.contains("-")))).collect(toList());
for(RoleDto r : sorted)
System.out.println(r.getName());
However the output is
Business Practitioner - Expert
Developer - Expert
Developer - Master
Business Practitioner - Master
Developer - Professional
Business Practitioner - Professional
Business Practitioner
Developer
Can someone please help me achieve the expected result
CodePudding user response:
I would suggest changing your RoleDto to have two attributes: String role and String level
Now the code for sorting List would look like:
Comparator<RoleDto> compareByRoleAndLevel = Comparator
.comparing(RoleDto::getRole)
.thenComparing(RoleDto::getLevel);
List<RoleDto> sortedRoles = roles.stream()
.sorted(compareByRoleAndLevel)
.collect(Collectors.toList());
CodePudding user response:
You do not actually compare the names, the compare just checks whether or not the names contain "-", which is why you are getting all that do (in random order) before all that don't (in random order). If you can change the Dto, see the answer of @Orr, otherwise you could do the name split/compare in place, like this:
final List<RoleDto> sorted =
roles.stream()
.sorted(
comparing(
RoleDto::getName,
comparing((String s) -> s.split(" - ")[0])
.reversed()
.thenComparing(s -> s.split(" - ").length)
.reversed()
.thenComparing(s -> s.split(" - ")[1])))
.collect(toList());
The reversing may seem a little unintuitive, but effectively every reverse reverses all the previous comparisons, so the first comparison get reversed twice. To skip that, you could instead write:
final List<RoleDto> sorted =
roles.stream()
.sorted(
comparing(
RoleDto::getName,
comparing((String s) -> s.split(" - ")[0])
.thenComparing(s -> -s.split(" - ").length)
.thenComparing(s -> s.split(" - ")[1])))
.collect(toList());
(notice the minus sign in the middle compare)