Function should return optional of most frequent last name (if it encountered at least two times) or optional empty if number of last names is the same or list of users is empty
This is what i came up with, but it doesnt return Optional.empty
@Override
public Optional<String> getMostFrequentLastName(final List<User> users) {
return users.stream()
.map(User::getLastName)
.distinct()
.collect
(Collectors.groupingBy(
Function.identity(),
Collectors.summingInt(w -> 1)
))
.entrySet()
.stream()
.filter(stringIntegerEntry -> stringIntegerEntry.getValue() >= 2)
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.map(Map.Entry::getKey)
.findFirst();
}
This is my test class
public static void main(String[] args) {
Optional<String> optionalS = Stream.of(new User("name1"),
new User("name1"), new User("name2"), new User("name2"))
.map(User::getLastName)
.collect
(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
))
.entrySet()
.stream()
.filter(stringIntegerEntry -> stringIntegerEntry.getValue() >= 2)
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.map(Map.Entry::getKey)
.findFirst();
System.out.println(optionalS.toString());
}
Here is the awnser
Optional[name2]
But should be
Optional[empty]
You may use
Optional<String> optionalS =
Stream.of(new User("name1"), new User("name1"), new User("name2"), new User("name2"))
.collect(Collectors.groupingBy(User::getLastName, Collectors.counting()))
.entrySet()
.stream()
.filter(entry -> entry.getValue() >= 2)
.reduce((e1, e2) -> e1.getValue() < e2.getValue()? e2:
e1.getValue() > e2.getValue()? e1:
new AbstractMap.SimpleImmutableEntry<>(null, e1.getValue()))
.map(Map.Entry::getKey);
System.out.println(optionalS.toString());
Getting the maximum value is a form of Reduction. Since you want to get an empty optional in case of a tie, the simplest solution is to write the reduction function explicitly, use the Map.Entry
with the bigger value if there is one, otherwise construct a new Map.Entry
with a null
key.
The result of the reduction is already an Optional
, which will be empty if there were no elements (with a count >=2
). So the last map
step is applied on an Optional
. If already empty, the map
function won’t be evaluated and the resulting Optional
stays empty. If the optional is not empty, but Map.Entry::getKey
evaluates to null
, the resulting optional will be empty.