How to find counts of distinct objects using Java streams
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()));
user1015388
Updated on July 19, 2022Comments
-
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?