Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Count properties of objects in list using java 8

So let's suppose I have an Arraylist of the object Animal. That class of the object is like this:

class Animal{
    String Name;//for example "Dog"
    String Color
}

What I want to do, is count how many different colors exist for each animal in the ArrayList and put them in a Map<String,Integer> where String is the Name and Integer is for the number of different colors.

For example if there are 4 black dogs and 1 white the equivalent put to the map would be

map.put("Dog",2);

I know it can be done using Stream but I can't find out how.

like image 984
dkaz Avatar asked Apr 11 '16 08:04

dkaz


People also ask

How do you count elements in an ArrayList?

The size of an ArrayList can be obtained by using the java. util. ArrayList. size() method as it returns the number of elements in the ArrayList i.e. the size.

What does count () do in Java?

Stream count() method in Java with examples long count() returns the count of elements in the stream. This is a special case of a reduction (A reduction operation takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation).


2 Answers

This should work:

    Map<String, Integer> map = animal.stream().collect(
            Collectors.groupingBy(
                    Animal::getName,
                    Collectors.collectingAndThen(
                            Collectors.mapping(Animal::getColor, Collectors.toSet()),
                            Set::size)
                    )
            );

Here some test-code:

public static void main(String[] args) {
    List<Animal> animal = new ArrayList<>();
    animal.add(new Animal("Dog","black"));
    animal.add(new Animal("Dog","black"));
    animal.add(new Animal("Dog","blue"));
    animal.add(new Animal("Cat","blue"));
    animal.add(new Animal("Cat","white"));

    Map<String, Integer> map = animal.stream().collect(
            Collectors.groupingBy(
                    Animal::getName,
                    Collectors.collectingAndThen(
                            Collectors.mapping(Animal::getColor, Collectors.toSet()),
                            Set::size)
                    )
            );

    for(Entry<String, Integer> entry:map.entrySet()) {
        System.out.println(entry.getKey()+ " : "+entry.getValue());
    }

}

gives

Cat : 2
Dog : 2

Note: this answer was inspired by this SO post: https://stackoverflow.com/a/30282943/1138523

like image 23
Raphael Roth Avatar answered Oct 13 '22 15:10

Raphael Roth


What you want to do is a grouping operation using the name property as key. That’s the easy part. Trickier is to express “count of distinct colors” as downstream collector. Since there is no such collector in the JRE, we have to built one, utilizing a Set storage. Note that even if there was a built-in one, it had to use a similar storage under the hood. So we map the elements to colors, collect them into Sets (which implies keeping distinct values only) and finish by querying the size:

Map<String, Integer> map = animalStream.collect(
    Collectors.groupingBy(Animal::getName,
        Collectors.collectingAndThen(
            Collectors.mapping(Animal::getColor, Collectors.toSet()),
            Set::size)));
like image 163
Holger Avatar answered Oct 13 '22 17:10

Holger