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?
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()));
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()));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With