Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java stream collect counting to field

Is it possible use Collectors.groupingBy() with Collectors.counting() to count to the field of a custom object instead of creating a map and transforming it afterwards.

I have a list of users, like this:

public class User {
    private String firstName;
    private String lastName;
    // some more attributes

    // getters and setters
}

I want to count all users with the same first and last name. Therefore I have custom object looking like this:

public static class NameGroup {
    private String firstName;
    private String lastName;
    private long count;

    // getters and setters
}

I can collect the name groups using this:

List<NameGroup> names = users.stream()
        .collect(Collectors.groupingBy(p -> Arrays.asList(p.getFirstName(), p.getLastName()), Collectors.counting()))
        .entrySet().stream()
        .map(e -> new NameGroup(e.getKey().get(0), e.getKey().get(1), e.getValue()))
        .collect(Collectors.toList());

With this solution I have to group the users first to a map and transform it afterwards to my custom object. Is it possible to count all names directly to nameGroup.count to avoid iterating twice over the list (or map) and improve the performance?

like image 935
Samuel Philipp Avatar asked Apr 30 '19 18:04

Samuel Philipp


People also ask

What does collect () do in Java?

collect() is one of the Java 8's Stream API's terminal methods. It allows us to perform mutable fold operations (repackaging elements to some data structures and applying some additional logic, concatenating them, etc.) on data elements held in a Stream instance.

Which downstream collector can count the value?

Collector collectingAndThen(Collector downstream, Function finisher): This method allows us to perform another operation on the result after collecting the input element of collection.


1 Answers

You could collect directly to NameGroup.count, but it would be less efficient than what you have, not more.

Internally, the map is being used to maintain a data structure that can efficiently track the name combinations and map them to counts which are updated as more matches are found. Reinventing that data structure is painful and unlikely to result in meaningful improvements.

You could try to collect NameGroups directly in the map instead of going via a count, but most approaches for that would, again, be more expensive than what you have now, and certainly much more awkward.

Honestly: what you have now is perfectly good, and not inefficient in any ways that are important. You should almost certainly stick to what you have.

like image 168
Louis Wasserman Avatar answered Sep 20 '22 13:09

Louis Wasserman