Java8 - 使用流映射而不收集性能

ale*_*ger 2 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 
Run Code Online (Sandbox Code Playgroud)

问题

  • 每次调用都会addWeeks返回 aSet<SeasonBuilder>并将所有内容收集到 a 中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());
    
    Run Code Online (Sandbox Code Playgroud)
  • 内存不足错误..... 当可能时周的大小为 15

问题

  • 我应该使用除map后跟之外的方法链flatmap吗?
  • addWeeks该如何修改,以便我不必将所有内容都收集到一个Set?
    • 我应该返回一个Stream<SeasonBuilder>吗?我flatmap可以Stream吗?

更新:

感谢大家的帮助!

我已经把这些方法的代码放在了一个要点中

感谢@Holger 和@lexicore 建议返回一个Stream<SeasonBuilder>in addWeeks。正如@lexicore 所预测的那样,性能略有提高

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

语境

我正在创建梦幻足球赛季的所有可能排列,这些排列将在其他地方用于统计分析。在 4 支球队、14 周的赛季中,对于任何给定的一周,可能存在三种不同的可能性

  • (1 对 2) , (3 对 4)
  • (1 对 3) , (2 对 4)
  • (1 对 4) , (2 对 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 支球队的赛季会变得更加疯狂。

lex*_*ore 5

你的整个构造一开始就非常可疑。如果您对性能感兴趣,那么显式生成所有排列不太可能是一种好方法。

我也并不认为收集到一组,并再次流是性能问题。

但无论如何,要回答你的问题:你为什么不返回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
}
Run Code Online (Sandbox Code Playgroud)

你不需要map/flatMap然后,只需一个flatMap

sbStream = sbStream.flatMap(sb -> sb.addWeeks(possibleWeeks));
Run Code Online (Sandbox Code Playgroud)

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