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