1

I'm receiving a List of Entity, I need to group them by 2 fields (periodMonth and periodYear) and return as a new list.

To store the groups, I created a class GroupEntity.

The fields that I must use to group doesn't belong to the Entity itself, but to an embeddable class called EntityPK.

Here's the code of these classes:

Entity

@Entity
@Table(name = "Entity")
public class Entity {

    @EmbeddedId
    private EntityPK entityPk;

    @Column
    private String someValue;

EntityPK

@Embeddable
public class EntityPK {

    @Column
    private String periodMonth;

    @Column
    private String periodYear;

Group class

public class GroupOfEntity {

    private String periodMonth;

    private String periodYear;

    private List<Entity> entities;

I could iterate over that list and create a map with periodMonth/Year as key, and the List as values, like this:

Set<GroupEntity> listOfGroupEntity = new HashSet<GroupEntity>();
        for(Entity entity: listOfEntity) {
            GroupEntity groupEntity = new GroupEntity();
            groupEntity.setPeriodMonth(entity.getEntityPk().getPeriodMonth());
            groupEntity.setPeriodYear(entity.getEntityPk().getPeriodYear());
            Optional<GroupEntity> findFirst = listOfGroupEntity.stream().filter(a -> a.equals(groupEntity)).findFirst();
            if(findFirst.isPresent()) {
                findFirst.get().getEntities().add(entity);
            }else {
                listOfGroupEntity.add(groupEntity);
            }
        }

But how could I do that using stream?

Something like

List<GroupEntity> groupEntities 
    = listOfEntities.stream().collect(Collectors.groupingBy(Entity::getEntityPk::getPeriodMonth,Entity::getEntityPk::getPeriodYear)

And create GroupEntity object for each group, with these entities.

Is it possible?

fsakiyama
  • 337
  • 3
  • 13

2 Answers2

3

Assuming that EntityPK implements equals and hashCode, you first build Map<EntityPK, List<Entity>>, then map that to List<GroupOfEntity>.

Assuming GroupOfEntity has appropriate constructor, you'd do it like this:

List<GroupOfEntity> groupEntities = listOfEntities.stream()
        .collect(Collectors.groupingBy(Entity::getEntityPk))
        .entrySet().stream()
        .map(e -> new GroupOfEntity(e.getKey().getPeriodMonth(),
                                    e.getKey().getPeriodYear(),
                                    e.getValue()))
        .collect(Collectors.toList());
Andreas
  • 154,647
  • 11
  • 152
  • 247
1

First, do this:

 Map<EntityPK, List<Entity>> groupEntities =
 entities.stream().collect(Collectors.groupingBy(Entity::getEntityPk));

And then create GroupOfEntity from the above Map. These two steps can be combined as well.

This is the combined step to further stream the map and create GroupOfEntity:

List<GroupOfEntity> groupEntities
        = entities.stream().collect(Collectors.groupingBy(Entity::getEntityPk)).entrySet()
        .stream().map(e -> new GroupOfEntity(e.getKey().getPeriodMonth(), e.getKey().getPeriodYear(), e.getValue()))
        .collect(Collectors.toList());

Please refer the full running sample at github

fiveelements
  • 3,649
  • 1
  • 17
  • 16
  • I tested both your and @Andreas solution, and both worked! Since he answered first, ill mark his answer. – fsakiyama Jul 26 '19 at 21:34