Which is efficient way to bifurcate List of nested object list ? java 8 flatmap vs for each?

AshwinK :

I've a Terminal object:

class Terminal{

    List<TerminalPeriodApplicability> periods= new ArrayList<>();
    //few other attributes

    //getters & setters

}

TerminalPeriodApplicability object:

class TerminalPeriodApplicability{

    String name;
    boolean isRequired;
    //getters & setters
}

I want to bifurcate names of TerminalPeriodApplicability into optional & mandatory Sets based on isRequired's value.

I've tried two approaches of it. One with two forEach and the other with flatMap.

List<Terminal> terminals= getTerminals();
Set<String> mandatoryPeriods = new HashSet<>();
Set<String> optionalPeriods = new HashSet<>();

Approach 1:

terminals.forEach(terminal -> terminal.getApplicablePeriods().forEach(period->{
    if(period.getIsRequired())
        mandatoryPeriods.add(period.name());
    else
        optionalPeriods.add(period.name());
}));

Approach 2:

List<TerminalPeriodApplicability> applicablePeriods = terminals
                .stream()
                .flatMap(terminal -> terminal.getApplicablePeriods().stream())
                .collect(Collectors.toList());

applicablePeriods.forEach(period->{
    if(period.getIsRequired())
        mandatoryPeriods.add(period.name());
    else
        optionalPeriods.add(period.name());
});

I would like to know which approach is more efficient in terms of time & space complexity. Or is there any better solution to solve this problem?

Eran :

You can use a different terminal operation in your flatMap version - partitioningBy instead of toList - and avoid the second forEach:

Map<Boolean,List<TerminalPeriodApplicability>> periods = terminals
            .stream()
            .flatMap(terminal -> terminal.getApplicablePeriods().stream())
            .collect(Collectors.partitioningBy(TerminalPeriodApplicability::getIsRequired);

or

Map<Boolean,Set<TerminalPeriodApplicability>> periods = terminals
            .stream()
            .flatMap(terminal -> terminal.getApplicablePeriods().stream())
            .collect(Collectors.partitioningBy(TerminalPeriodApplicability::getIsRequired,
                                               Collectors.toSet());

Correction: Since you want the two Sets to contain Strings instead of TerminalPeriodApplicability instances, it should be:

Map<Boolean,Set<String>> periods = terminals
            .stream()
            .flatMap(terminal -> terminal.getApplicablePeriods().stream())
            .collect(Collectors.partitioningBy(TerminalPeriodApplicability::getIsRequired,
                                               Collectors.mapping(TerminalPeriodApplicability::name,
                                                                  Collectors.toSet()));

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=329597&siteId=1