Java8 - 使用Streams进行映射而不收集性能

时间:2016-12-14 10:21:30

标签: java lambda java-8 java-stream collectors

指数增长的流

我有Stream 指数增长用于创建排列。因此,每次调用addWeeks都会增加Stream中的元素数量。

Stream<SeasonBuilder> sbStream = sbSet.stream();

for (int i = 1; i <= someCutOff; i++) {
    sbStream = sbStream.map(sb -> sb.addWeeks(possibleWeeks))
                       .flatMap(Collection::stream); 
}

// Collect SeasonBuilders into a Set
return sbStream.collect(Collectors.toSet());   // size > 750 000 

问题

  • 每次调用addWeeks都会返回Set<SeasonBuilder>并将所有内容收集到Set需要一段时间。
  • addWeeks不是静态的,需要在流中的每个SeasonBuilder上调用,每次循环

    public Set<SeasonBuilder> addWeeks(
        final Set<Set<ImmutablePair<Integer, Integer>>> possibleWeeks) {
            return possibleWeeks.stream()
                    .filter(containsMatchup())   // Finds the weeks to add
                    .map(this::addWeek)   // Create new SeasonBuilders with the new week
                    .collect(Collectors.toSet());
    
  • 内存不足错误.....如果可能,周数大小= 15

问题

  • 我应该使用 map 以外的方法链,然后是 flatmap 吗?
  • 如何修改addWeeks以便我不必将所有内容收集到Set中?
    • 我应该退回Stream<SeasonBuilder>吗?我可以flatmap Stream吗?

更新

感谢大家的帮助!

我已将方法的代码放在gist

感谢@Holger和@lexicore建议在Stream<SeasonBuilder>中返回addWeeks。正如@lexicore预测的那样,性能略有提升

我尝试使用parallelStream()并且性能没有显着变化

上下文

我正在创建Fantasy Football季节的所有可能的排列,这些排列将用于其他地方进行统计分析。在一个为期14周的4人团队中,对于任何一周,可能有三种不同的可能性

  • (1 vs 2),(3 vs 4)
  • (1 vs 3),(2 vs 4)
  • (1 vs 4),(2 vs 3)

要解决这个问题,请插入排列,我们可能会有所有可能的季节。完成!但是等等......如果第1队只参加第2队,那么其他队伍会很伤心。因此对排列有一些限制。

每支球队必须在大致相同的时间内相互比赛(即1队在一个赛季中不能与队3比赛10次)。在这个例子中 - 4支球队,14周 - 每支球队都有5次参加另一支球队的比赛。因此,在创建排列时必须进行某种过滤,以避免无效的季节。

这更有趣的地方是:

  • 6个团队联盟 - 15个可能的周
  • 8个团队联盟 - 105个可能的周
  • 10个团队联盟 - 945个可能的周

我正在尝试尽可能优化性能,因为要创建很多排列。考虑到限制,一个4人队,为期14周的赛季创造了756 756(= 14!/(5!5!4!))可能的赛季。 6队或8队的赛季变得更加疯狂。

1 个答案:

答案 0 :(得分:4)

你的整个建筑开始时非常可疑。如果您对性能感兴趣,那么明确生成所有排列不太可能是一种好方法。

我也不相信收集设置和再次流媒体是 性能问题。

但是,回答你的问题:你为什么不直接从Stream<SeasonBuilder>返回addWeeks,为什么要收集它先设置?直接返回流,不收集:

public Stream<SeasonBuilder> addWeeks(
    final Set<Set<ImmutablePair<Integer, Integer>>> possibleWeeks) {
        return possibleWeeks.stream()
                .filter(containsMatchup())   // Finds the weeks to add
                .map(this::addWeek);   // Create new SeasonBuilders with the new week
}

您不需要map / flatMap,只需要一个flatMap

sbStream = sbStream.flatMap(sb -> sb.addWeeks(possibleWeeks));

但无论如何这对你的表现都没有帮助。