56

Is there a better way to count int occurrences with Java8

int[] monthCounter = new int[12];
persons.stream().forEach(person -> monthCounter[person.getBirthday().getMonthValue() - 1]++);
skiwi
  • 66,971
  • 31
  • 131
  • 216
Du_
  • 915
  • 1
  • 9
  • 16

6 Answers6

122

Try:

 Map<Integer, Long> counters = persons.stream()
     .collect(Collectors.groupingBy(p -> p.getBirthday().getMonthValue(), 
         Collectors.counting()));
Rafael
  • 563
  • 4
  • 10
Brian Goetz
  • 90,105
  • 23
  • 150
  • 161
6

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());
Cuga
  • 17,668
  • 31
  • 111
  • 166
3

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

Community
  • 1
  • 1
itohro
  • 151
  • 5
2

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)));
avigaild
  • 73
  • 1
  • 2
  • 6
0

Already answered. Small Suggestion from my side inorder to eliminate null pointer exception ie From the stream null will throw java.lang.UnsupportedOperationException, java.lang.NullPointerException

Map<Integer, Long> birthdayCount = persons.stream()
                                    .filter(Objects::nonNull) // filter out null object
                                    .filter(p->Objects.nonNull(p.getBirthday())) // filter out null birthdays
                                    .collect(Collectors.groupingBy(p -> 
                                                 p.getBirthday().getMonthValue(), 
                                                 Collectors.counting()));
-5
int size = persons.stream().count()
Huy Le
  • 1,042
  • 9
  • 10
  • 2
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – DimaSan Jun 21 '17 at 07:17
  • 1
    `count()` returns long you need to cast to int, so this doesn't compile. It wouyld be `int size = (int) persons.stream().count()` – Pau Jul 03 '17 at 06:31