1

So I have the following object:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class StakeHolderTypesDepartmentsNotifications {

    private StakeholderTypeEntity stakeholderTypeEntity;
    private StakeholderDepartmentEntity stakeholderDepartmentEntity;
    private StakeholderEntity stakeholderEntity;
    private StakeholderNotificationEntity stakeholderNotificationEntity;
}

So I initially had a list of this object, and I turned it into a Map<String, List<StakeHolderTypesDepartmentsNotifications> where the key is stakeholderDepartmentEntity.getId():

Map<String, List<StakeHolderTypesDepartmentsNotifications>> map =
    stakeholders.stream()
                .filter(entry -> entry.getStakeholderDepartmentEntity() != null)
                .collect(groupingBy(
                        entry -> entry.getStakeholderDepartmentEntity().getId()));

However now I would like the following:

Map<String, Map<String,List<StakeHolderTypesDepartmentsNotifications>>

Where the key of the top level map is stakeholderTypeEntity.getId(), where the value is the Map from above, where the key is the stakeholderDepartmentEntity.getId()

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • I don't understand the problem, you want to change the previous `Map` to new `Map` by java stream? Or do you want to create new `Map` by streaming the previous `Map`? – AP11 Jan 21 '21 at 09:15

3 Answers3

3

You can achieve it using another groupingBy as a downstream collector:

Map<String, Map<String, List<StakeHolderTypesDepartmentsNotifications>>> resultMap = 
    stakeholders
            .stream()
            .filter(e -> e.getStakeholderTypeEntity() != null)
            .filter(e -> e.getStakeholderDepartmentEntity() != null)
            .collect(Collectors.groupingBy(
                    e -> e.getStakeholderDepartmentEntity().getId(),
                    Collectors.groupingBy(
                        e -> e.getStakeholderTypeEntity().getId())));

Of course, an additional check whether getStakeholderTypeEntity() doesn't return null might make sense.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
2
Map<String, Map<String, List<StakeHolderTypesDepartmentsNotifications>>> result = stakeholders
    .stream()
    .filter(e -> e.getStakeholderTypeEntity() != null && 
                 e.getStakeholderDepartmentEntity() != null)
    .collect(groupingBy(e -> e.getStakeholderTypeEntity().getId(), 
             groupingBy(e -> e.getStakeholderDepartmentEntity().getId())));
    
Lino
  • 19,604
  • 6
  • 47
  • 65
1

You should be able to do this by applying Collectors.groupingBy several times:

Map<String, Map<String,List<StakeHolderTypesDepartmentsNotifications>>> result = 
    stakeholders
        .stream()
        .filter(entry -> Objects.nonNull(entry.getStakeholderTypeEntity())
            && Objects.nonNull(entry.getStakeholderDepartmentEntity()))
        .collect(
            Collectors.groupingBy(
                entry -> entry.getStakeholderTypeEntity().getId(),
                Collectors.groupingBy(
                    entry -> entry.getStakeholderDepartmentEntity().getId()
                )
            )
        );

Aside comment: it's worth to refactor the names of the fields to remove redundant verbosity:

public class StakeHolderTypesDepartmentsNotifications {
    // just a model for an sql query that joins across all these tables
    private StakeholderTypeEntity type;
    private StakeholderDepartmentEntity department;
    private StakeholderEntity stakeholder;
    private StakeholderNotificationEntity notification;
}

Then building the map would look as follows:

Map<String, Map<String,List<StakeHolderTypesDepartmentsNotifications>>> result = 
    stakeholders
        .stream()
        .filter(entry -> Objects.nonNull(entry.getType()) && Objects.nonNull(entry.getDepartment()))
        .collect(
            Collectors.groupingBy(
                entry -> entry.getType().getId(),
                Collectors.groupingBy(-> entry.getDepartment().getId())
            )
        );
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42