Count int occurrences with Java8

Try:

 Map<Integer, Long> counters = persons.stream()
     .collect(Collectors.groupingBy(p -> p.getBirthday().getMonthValue(), 
         Collectors.counting()));

There's a few variations this could take.

You can use Collectors.summingInt() to use Integer instead of the Long in the count.

If you wanted to skip the primitive int array, you could store the counts directly to a List in one iteration.

Count the birth months as Integers

Map<Integer, Integer> monthsToCounts = 
        people.stream().collect(
                Collectors.groupingBy(p -> p.getBirthday().getMonthValue(), 
                Collectors.summingInt(a -> 1)));

Store the birth months in a 0-based array

int[] monthCounter = new int[12];
people.stream().collect(Collectors.groupingBy(p -> p.getBirthday().getMonthValue(), 
                        Collectors.summingInt(a -> 1)))
                        .forEach((month, count) -> monthCounter[month-1]=count);

Skip the array and directly store the values to a list

List<Integer> counts = people.stream().collect(
        Collectors.groupingBy(p -> p.getBirthday().getMonthValue(), 
        Collectors.summingInt(a -> 1)))
        .values().stream().collect(Collectors.toList());

With Eclipse Collections (formerly GS Collections), you can make use of a data structure called Bag that can hold the number of occurrences of each element.

Using IntBag, the following will work:

MutableList<Person> personsEC = ListAdapter.adapt(persons);
IntBag intBag = personsEC.collectInt(person -> person.getBirthDay().getMonthValue()).toBag();

intBag.forEachWithOccurrences((month, count) -> System.out.println("Count of month:" + month + " is " + count));

If you want to make use of an array to keep track of the count, you can combine with the Arrays.setAll() approach Brian pointed out in another answer.

int[] monthCounter  = new int[12];
MutableList<Person> personsEC = ListAdapter.adapt(persons);
IntBag bag = personsEC.collectInt(person -> person.getBirthDay().getMonthValue()).toBag();
Arrays.setAll(monthCounter, bag::occurrencesOf);
System.out.println(IntLists.immutable.with(monthCounter));

This code will also work with Java 5 – 7 if you use anonymous inner classes instead of lambdas.

Note: I am a committer for Eclipse Collections


If you would like to get Integer to Integer map, you can do the following.

Map<Integer, Integer> counters = persons.stream()
    .collect(Collectors.groupingBy(
        p -> p.getBirthday().getMonthValue(),
        Collectors.reducing(0, e -> 1, Integer::sum)));