【问题标题】:Which is efficient way to bifurcate List of nested object list ? java 8 flatmap vs for each?哪种方法是对嵌套对象列表进行分叉的有效方法? java 8 flatmap vs for each?
【发布时间】:2019-05-06 09:00:38
【问题描述】:

我有一个Terminal 对象:

class Terminal{

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

    //getters & setters

}

TerminalPeriodApplicability对象:

class TerminalPeriodApplicability{

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

我想根据isRequired 的值将TerminalPeriodApplicability 的名称分为optionalmandatory Sets。

我尝试了两种方法。一个有两个forEach,另一个有flatMap

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

方法一

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());
});

我想知道哪种方法在时间和空间复杂性方面更有效。或者有没有更好的办法来解决这个问题?

【问题讨论】:

  • forEach 方法可以简化为terminals.forEach(terminal -&gt; terminal.getApplicablePeriods().forEach(period -&gt; (period.getIsRequired()? mandatoryPeriods: optionalPeriods).add(period.name()) ));,不过,this answer 的 Stream 方法看起来更干净……

标签: java foreach java-8 java-stream


【解决方案1】:

您可以在 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());

更正:由于您希望两个 Sets 包含 Strings 而不是 TerminalPeriodApplicability 实例,因此应该是:

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

【讨论】:

  • 正确答案是这个Map&lt;Boolean,Set&lt;String&gt;&gt; periods = terminals .stream() .flatMap(terminal -&gt; terminal.getApplicablePeriods().stream()) .collect(Collectors.partitioningBy(TerminalPeriodApplicability::getIsRequired,Collectore.mapping(TerminalPeriodApplicability::getName,Collectors.toSet()));
  • @HadiJ 哦,我没有注意到 OP 将名称 Strings 放入集合中。谢谢。我会解决的。
  • 哇。这很棒 !我对 partitioningBy 方法了解不多。谢谢@Eran & HadiJ
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-01
  • 2022-01-18
相关资源
最近更新 更多