How to find counts of distinct objects using Java streams

11,890

Solution 1

You can get it using Collectors.groupingBy the id attribute and then counting its occurrences as:

List<Thing> objects = new ArrayList<>(); // initalise as in the question 
Map<String, Long> countForId = objects.stream()
        .collect(Collectors.groupingBy(Thing::getId, Collectors.counting()));

Solution 2

one could also use the toMap collector:

lst.stream().collect(toMap(Thing::getId, v -> 1, Math::addExact));

creates a Map<String, Integer> where the Thing::getId is the key mapper used to select the map keys and v -> 1 is the value mapper used to select the map values and in the case of a key collision we add the corresponding values with the merge function Math::addExact.

or Map::merge:

Map<String, Integer> accumulator = new HashMap<>();
lst.forEach(t -> accumulator.merge(t.getId(), 1, Math::addExact));

Same idea as above, if the Thing::getId is already present in the accumulator map, we merge them with Math::addExact otherwise we accumulate the provided key and value into the map.

if the order matters as shown in your post, then instead of HashMap above, you can use a LinkedHashMap.

You could also provide a map into which the elements are to be accumulated into to preserve order in the toMap collector with:

lst.stream().collect(toMap(Thing::getId, v -> 1, Math::addExact, LinkedHashMap::new));

or using the groupingBy collector:

lst.stream()
   .collect(Collectors.groupingBy(Thing::getId, 
                LinkedHashMap::new,
                Collectors.counting()));
Share:
11,890
user1015388
Author by

user1015388

Updated on July 19, 2022

Comments

  • user1015388
    user1015388 almost 2 years

    I have a list of Thing objects:

    class Thing {
        public String id;
        public String name;
    }
    

    List<Thing> lst contains following;

    [{'1', 'AB'},{'2', 'CD'},{'1', 'AB'},{'1','AB'},{'2','CD'},{'3','EF'}]
    

    Now I want to use Java streams or any util functions to get a distinct count on id: I want the output to be,

    id   count
    1    3
    2    2 
    3    1
    

    How can I achieve this?