Home > Enterprise >  How to group objects by their enum values?
How to group objects by their enum values?

Time:05-28

I would like to write a program which analyses properties of houses in a neighborhood. For this I have 3 enums in my program which include the different properties, i.e. size, color and shape of the houses.

The houses are defined the following way:

public House(Size size, Color color, Shape shape) {
        this.size = size;
        this.color = color;
        this.shape = shape;
    }

Now I have an ArrayList with a few hundred different houses and I would like to count how many houses each have which combination of properties (for example "how many houses are big, blue and rectangular?"). If I would create a new ArrayList for each possible combination of these properties I would have more than 30 lists and tons of if-loops in my code.

Is there an easier way to group houses with the same enum values together?

Thank you very much in advance.

CodePudding user response:

You can use the Java Stream API to filter your list then produce a count, for example;

long smallRedRectangularHousesCount = houses
        .stream()
        .filter(h -> h.getSize() == Size.SMALL &&
                h.getColor() == Color.RED &&
                h.getShape() == Shape.RECTANGLE
        )
        .count();

CodePudding user response:

First, let's get some example enum values.

enum Size
{ TINY, SMALL, MEDIUM, LARGE, MANSION }

enum Color
{ BEIGE, BROWN, GREEN, GREY }

enum Shape
{ RECTANGLE, SQUARE, ROUND }

I would redefine that class House as a record for brevity and simplicity.

Also, tracking real properties requires additional fields beyond just size, color, and shape. For our purposes here, I will add a UUID to identify each individual house.

record House ( UUID id , Size size, Color color, Shape shape ) {}

Some sample data.

List < House > houses =
        List.of(
                new House( UUID.fromString( "d23d3532-7e43-441a-ac49-d2bc37d884a2" ) , Size.MEDIUM , Color.BROWN , Shape.RECTANGLE ) ,
                new House( UUID.fromString( "e0e7d84c-8500-4372-a6ac-6b601e50b31e" ) , Size.LARGE , Color.BROWN , Shape.ROUND ) ,
                new House( UUID.fromString( "ab251020-fc2b-4f3a-ae92-4cd6da850ac0" ) , Size.MEDIUM , Color.GREEN , Shape.RECTANGLE ) ,
                new House( UUID.fromString( "c675f75e-335e-418e-b805-d6563c2c6e0f" ) , Size.LARGE , Color.BROWN , Shape.ROUND )
        );

If you simply want to search the list for a particular combination of properties, you can use streams to filter as shown in Answer by Idan Elhalwani.

long countBrown = houses.stream().filter( house -> house.color().equals( Color.BROWN ) ).count();

3

For multiple criteria (color and shape as well as size), use the && syntax seen in the other Answer.

Your Question is somewhat confused. You seem to be asking about grouping all houses by all possible combinations of criteria. Doing so would be a good idea if you are doing many mare queries than data changes. Doing the grouping ahead of time is much work, but is worth it if you are doing many queries.

To do the grouping, let's define another record, HouseProfile, to contain only the three fields of Size, Color, and Shape. We will use loops to instantiate objects of all possible combinations.

record HouseProfile( Size size , Color color , Shape shape ) { }

We can determine all possible combinations quite easily. Calling values on an enum returns an array of all the named objects on that enum. We can then loop on that array.

We do this for each of your 3 enums: Size, Color, and Shape. As we go through these, we filter the list of houses that match each enum object. We end up with a list of houses that match each combination of enum objects. That list might be empty, or might have houses. We put each list in a Map, a collection of key-value pairings. We use HouseProfile as the key to our map, leading to a List of type House.

First define our map, to hold results.

Map < HouseProfile, List < House > > housesByProfile = new HashMap <>();

Then loop all values of each enum.

for ( Size size : Size.values() )
{
    List < House > sized = houses.stream().filter( house -> house.size.equals( size ) ).toList();
    for ( Color color : Color.values() )
    {
        List < House > sizedAndColored = sized.stream().filter( house -> house.color.equals( color ) ).toList();
        for ( Shape shape : Shape.values() )
        {
            List < House > sizedAndColoredAndShaped = sizedAndColored.stream().filter( house -> house.shape.equals( shape ) ).toList();
            housesByProfile.put( new HouseProfile( size , color , shape ) , sizedAndColoredAndShaped );
        }
    }
}

Dump to console.

System.out.println( "housesByProfile = "   housesByProfile );

If you read through the output, you will find each of three sample houses. Notice that for HouseProfile[size=LARGE, color=BROWN, shape=ROUND] we have a list of two House objects with IDs of "e0e7d84c-8500-4372-a6ac-6b601e50b31e" & "c675f75e-335e-418e-b805-d6563c2c6e0f".

housesByProfile = {HouseProfile[size=MANSION, color=GREEN, shape=RECTANGLE]=[], HouseProfile[size=MANSION, color=GREEN, shape=ROUND]=[], HouseProfile[size=SMALL, color=BROWN, shape=ROUND]=[], HouseProfile[size=LARGE, color=BEIGE, shape=SQUARE]=[], HouseProfile[size=MEDIUM, color=BROWN, shape=RECTANGLE]=[House[id=d23d3532-7e43-441a-ac49-d2bc37d884a2, size=MEDIUM, color=BROWN, shape=RECTANGLE]], HouseProfile[size=MANSION, color=BEIGE, shape=RECTANGLE]=[], HouseProfile[size=LARGE, color=GREEN, shape=SQUARE]=[], HouseProfile[size=MEDIUM, color=BEIGE, shape=ROUND]=[], HouseProfile[size=MEDIUM, color=BEIGE, shape=RECTANGLE]=[], HouseProfile[size=SMALL, color=BEIGE, shape=ROUND]=[], HouseProfile[size=SMALL, color=GREY, shape=RECTANGLE]=[], HouseProfile[size=TINY, color=GREEN, shape=SQUARE]=[], HouseProfile[size=MEDIUM, color=GREEN, shape=RECTANGLE]=[House[id=ab251020-fc2b-4f3a-ae92-4cd6da850ac0, size=MEDIUM, color=GREEN, shape=RECTANGLE]], HouseProfile[size=TINY, color=BEIGE, shape=SQUARE]=[], HouseProfile[size=SMALL, color=BROWN, shape=RECTANGLE]=[], HouseProfile[size=TINY, color=GREY, shape=ROUND]=[], HouseProfile[size=SMALL, color=GREEN, shape=ROUND]=[], HouseProfile[size=MANSION, color=BROWN, shape=RECTANGLE]=[], HouseProfile[size=LARGE, color=BROWN, shape=SQUARE]=[], HouseProfile[size=MEDIUM, color=GREEN, shape=ROUND]=[], HouseProfile[size=MEDIUM, color=GREY, shape=SQUARE]=[], HouseProfile[size=LARGE, color=GREY, shape=RECTANGLE]=[], HouseProfile[size=TINY, color=BROWN, shape=RECTANGLE]=[], HouseProfile[size=LARGE, color=BROWN, shape=ROUND]=[House[id=e0e7d84c-8500-4372-a6ac-6b601e50b31e, size=LARGE, color=BROWN, shape=ROUND], House[id=c675f75e-335e-418e-b805-d6563c2c6e0f, size=LARGE, color=BROWN, shape=ROUND]], HouseProfile[size=TINY, color=BROWN, shape=SQUARE]=[], HouseProfile[size=MANSION, color=BROWN, shape=SQUARE]=[], HouseProfile[size=SMALL, color=GREY, shape=SQUARE]=[], HouseProfile[size=SMALL, color=GREY, shape=ROUND]=[], HouseProfile[size=MEDIUM, color=GREY, shape=RECTANGLE]=[], HouseProfile[size=MEDIUM, color=GREEN, shape=SQUARE]=[], HouseProfile[size=MEDIUM, color=BROWN, shape=ROUND]=[], HouseProfile[size=TINY, color=BEIGE, shape=RECTANGLE]=[], HouseProfile[size=LARGE, color=BEIGE, shape=ROUND]=[], HouseProfile[size=TINY, color=BEIGE, shape=ROUND]=[], HouseProfile[size=LARGE, color=GREEN, shape=RECTANGLE]=[], HouseProfile[size=MEDIUM, color=BEIGE, shape=SQUARE]=[], HouseProfile[size=TINY, color=GREEN, shape=RECTANGLE]=[], HouseProfile[size=LARGE, color=GREEN, shape=ROUND]=[], HouseProfile[size=LARGE, color=BEIGE, shape=RECTANGLE]=[], HouseProfile[size=MANSION, color=GREEN, shape=SQUARE]=[], HouseProfile[size=MANSION, color=GREY, shape=RECTANGLE]=[], HouseProfile[size=MANSION, color=BEIGE, shape=SQUARE]=[], HouseProfile[size=TINY, color=BROWN, shape=ROUND]=[], HouseProfile[size=LARGE, color=GREY, shape=SQUARE]=[], HouseProfile[size=MANSION, color=GREY, shape=ROUND]=[], HouseProfile[size=LARGE, color=BROWN, shape=RECTANGLE]=[], HouseProfile[size=MEDIUM, color=BROWN, shape=SQUARE]=[], HouseProfile[size=MANSION, color=BROWN, shape=ROUND]=[], HouseProfile[size=SMALL, color=GREEN, shape=RECTANGLE]=[], HouseProfile[size=TINY, color=GREY, shape=RECTANGLE]=[], HouseProfile[size=LARGE, color=GREY, shape=ROUND]=[], HouseProfile[size=SMALL, color=GREEN, shape=SQUARE]=[], HouseProfile[size=SMALL, color=BEIGE, shape=SQUARE]=[], HouseProfile[size=TINY, color=GREEN, shape=ROUND]=[], HouseProfile[size=SMALL, color=BEIGE, shape=RECTANGLE]=[], HouseProfile[size=MEDIUM, color=GREY, shape=ROUND]=[], HouseProfile[size=MANSION, color=GREY, shape=SQUARE]=[], HouseProfile[size=SMALL, color=BROWN, shape=SQUARE]=[], HouseProfile[size=MANSION, color=BEIGE, shape=ROUND]=[], HouseProfile[size=TINY, color=GREY, shape=SQUARE]=[]}

Let’s use that map to get a count of houses meeting a combination of criteria.

int countLargeBrownRound = housesByProfile.get( new HouseProfile( Size.LARGE , Color.BROWN , Shape.ROUND ) ).size() ;

2

  • Related