I am trying to sort users based on their initials, and when initials are repeated, say 'Alex Fay' and 'Alba Finn', I have to sort them based on their age in descending order.
This is my current code:
List<SortedUser> sortedUserList = list.stream()
.sorted((a, b) -> {
int first = a.getName().charAt(0) a.getLastName().charAt(0);
int second = b.getName().charAt(0) b.getLastName().charAt(0);
if(first > second) {
return -1;
}
if(first < second) {
return 1;
}
return b.getAge() - a.getAge();
}).collect(Collectors.toList());
The problem with this code is that when I have initials 'AR' and 'EN', their sums are the same (147) - therefore first == second, and they appear one after the other in incorrect order. I also tried to compare the first name initial and the last name initial separately, but I still couldn't get it to work. What can I change in order to sort them the way I want it?
Sample input:
(name=Alexandre, lastName=Wuckert, age=66),
(name=Allan, lastName=Wehner, age=84),
(name=Bradley, lastName=Thompson, age=78),
(name=Bernice, lastName=Schoen, age=63)
Sample output:
(name=Bradley, lastName=Thompson, age=78),
(name=Bernice, lastName=Schoen, age=63),
(name=Allan, lastName=Wehner, age=84),
(name=Alexandre, lastName=Wuckert, age=66)
CodePudding user response:
Adding characters to sort on is unreliable since many pairs can sum to the same value. So you should build a String of initials rather than add them. Then use the following in your sort method.
String first = a.getName().charAt(0) "" a.getLastName().charAt(0);
String second = b.getName().charAt(0) "" b.getLastName().charAt(0);
int result = first.compareTo(second);
return result > 0 ? -1 : result < 0 ? 1 : b.getAge-a.getAge();
The above will sort in descending order based on the initials. If result == 0 then the ages will be used (as you did before).
Note: you could also do second.compareTo(first)
and then either swap 1 and -1
or swap the inequality signs
. Which ever makes more sense to you.
Here are some other alternatives for your consideration. I used a record to hold the User data.
record User(String getName, String getLastName, int getAge) {
}
List<User> list =
new ArrayList<>(List.of(new User("Alexandre", "Wuckert", 66),
new User("Allan", "Wehner", 84),
new User("Bradley", "Thompson", 78),
new User("Bernice", "Schoen", 63)));
- stream the list of users.
- the first argument is a
keyExtractor
to build the String on which to sort. In this case it is the user's initials. - then the String comparator,
String::compareTo
is used to sort on the initials. - if the initials are equal, then compare on the user's age.
- reversed() reverses are previous comparators to change from ascending (default) to descending.
List<User> sortedUsers = list.stream().sorted(Comparator
.comparing(
(User u) -> u.getName().charAt(0) ""
u.getLastName().charAt(0),
String::compareTo)
.thenComparing(User::getAge).reversed()).toList();
sortedUsers.forEach(System.out::println);
prints
User[getName=Bradley, getLastName=Thompson, getAge=78]
User[getName=Bernice, getLastName=Schoen, getAge=63]
User[getName=Allan, getLastName=Wehner, getAge=84]
User[getName=Alexandre, getLastName=Wuckert, getAge=66]
Note that you could also just sort the list in place and not use streams
as long as the list is mutable.
list.sort(Comparator.comparing(
(User u) -> u.getName().charAt(0) ""
u.getLastName().charAt(0),
String::compareTo)
.thenComparing(User::getAge).reversed());
CodePudding user response:
To make the code more readable and less error-prone, use Java 8 static methods of the Comparator
interface instead of placing a chain of conditions into a lambda expression.
Here's another way of implementing a comparator that will compare users based on the first letter of the first name, then by the first letter of the last name and finally by age in reversed:
Comparator<SortedUser> byFirstLettersAndAgeReversed =
Comparator.comparingInt((SortedUser user) -> user.getFirstName().charAt(0))
.thenComparingInt(user -> user.getLastName().charAt(0))
.thenComparingInt(SortedUser::getAge).reversed();
List<SortedUser> sortedUserList = list.stream()
.sorted(byFirstLettersAndAgeReversed)
.collect(Collectors.toList());
You can define a couple of comparators as public static
fields inside the reuse them you need to sort or compare these objects in a specific way.