Method to calculate the most frequent last name from list of given users with Java Stream API

Stirbul Alexei :

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]
Holger :

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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=143742&siteId=1