将 Java while 循环转换为 Stream 以提高性能

问题描述 投票:0回答:3

我有以下代码,由于必须将长流转换为数组,因此存在性能问题。 Board.getReachables() 方法返回一个流,因此能够使用流执行此 while 循环会提高性能。然而,我不确定如何继续。

 int counter = 1;
 while (check(board, counter)) {
   for (int i = 0; i < board.length; i++) {
     if (board[i] == counter) {
       for (Pos reach2 :
            Board.getReachables(currentTurn.getBoard().pos(i),
                                currentTurn.getBoard())
                 .toArray(Pos[]::new)) {
         if (board[currentTurn.getBoard().index(reach2)] == 0) {
           board[currentTurn.getBoard().index(reach2)] = counter + 1;
         }
       }
     }
   }
   counter++;
 }
java java-stream
3个回答
2
投票

将循环转换为流:

AtomicInteger counter = new AtomicInteger(1);
while (check(board, counter.get())) {
   for (int i = 0; i < board.length; i++) {
     if (board[i] == counter.get()) {
         Board.getReachables(currentTurn.getBoard().pos(i), currentTurn.getBoard())
         .filter(reach2 ->  board[currentTurn.getBoard().index(reach2)] == 0)
         .forEach(reach2 -> board[currentTurn.getBoard().index(reach2)] = counter.get() + 1);
     }
   }
   counter.incrementAndGet();
 }

counter
转换为
AtomicInteger
,因为它是在 lambda 中引用的,因此必须是 有效的最终

其他重构留给读者。


1
投票

未经测试,只是一个想法:

    while (check(board, counter)) {
        final int finalCounter = counter; //counter has to be final,
        //otherwise you get a "Local variable counter defined in an enclosing scope must be final or effectively final" error

        Arrays.stream(board) //IntStream
        .filter(b -> b == finalCounter) //  if (board[i] == counter) {
        .mapToObj(i ->Board.getReachables(currentTurn.getBoard().pos(i), currentTurn.getBoard())) //returns Stream<Stream<Pos>>
        .flatMap(Function.identity()) // flatmap maps Stream<Stream<Pos>> to a single (combined) Stream<Pos>
        .filter(pos -> board[currentTurn.getBoard().index(pos)] == 0)  //board[currentTurn.getBoard().index(reach2)] == 0
        .forEach(fp -> board[currentTurn.getBoard().index(fp)] = finalCounter +1); //board[currentTurn.getBoard().index(reach2)] = counter + 1;
        counter++;
    }

我认为有人不应该这样做,但这是一个有趣的练习。


0
投票

有两件事可以提高性能:

  1. 不要创建数组并对其进行循环,而只需在
    .forEach
    上调用
    Stream
  2. 仅计算一次指数。 不幸的是,这意味着使用
    if
    而不是
    .filter()
        int counter = 1;
        while (check(board, counter)) {
            for (int i = 0; i < board.length; i++) {
                if (board[i] == counter) {
                    Board currentTurnBoard = currentTurn.getBoard();
                    int   nextCounter      = counter + 1;
                    Board.getReachables(currentTurnBoard.pos(i), currentTurnBoard)
                         .forEach(reach2 -> {
                             int index = currentTurnBoard.index(reach2);
                             if (board[index] == 0) {
                                 board[index] = nextCounter;
                             }
                             return;
                         });
                }
            }
            counter++;
        }
© www.soinside.com 2019 - 2024. All rights reserved.