Какой эффективный способ раздвоить список вложенных объектов списка? Java 8 Flatmap против каждого? - PullRequest
1 голос
/ 06 мая 2019

У меня есть Terminal объект:

class Terminal{

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

    //getters & setters

}

TerminalPeriodApplicability объект:

class TerminalPeriodApplicability{

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

Я хочу разделить имена TerminalPeriodApplicability на optional & mandatory Set s на основе значения isRequired.

Я пробовал два подхода к этому. Один с двумя forEach, а другой с flatMap.

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

Подход 1 :

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

Подход 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());
});

Я хотел бы знать, какой подход является более эффективным с точки зрения сложности времени и пространства. Или есть лучшее решение для решения этой проблемы?

1 Ответ

6 голосов
/ 06 мая 2019

Вы можете использовать другую операцию терминала в вашей flatMap версии - partitioningBy вместо toList - и избегать второй forEach:

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

или

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

Исправление: поскольку вы хотите, чтобы два Set s содержали String s вместо TerminalPeriodApplicability экземпляров, оно должно быть:

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