Использование вложенных циклов в Java 8 - PullRequest
1 голос
/ 16 июня 2019

У меня есть код ниже, где я использую вложенный цикл for, и у меня есть некоторое условие, которое нарушает внутренний цикл for, и это улучшает производительность этого кода.

public static int getMaxValue(List<Integer> list) {
    int result = -1;
    for(int i=0; i<list.size(); i++) {
        for(int j=i+1; j<list.size(); j++) {
            if(list.get(j) - list.get(i) <= 0) break;
            if(list.get(j) - list.get(i) > result) {
                result = list.get(j) - list.get(i);
            }
        }
    }
    return result;
}

Теперь, как я могу использовать потоки Java 8 для выполнения той же логики? Я пришел с кодом ниже:

public static int getMaxValue(List<Integer> list) {
    int[] result = { -1 };
    IntStream.range(0, list.size()).forEach(i -> {
        IntStream.range(i + 1, list.size()).forEach(j -> {
            if(list.get(j) - list.get(i) <= 0) return;

            if(list.get(j) - list.get(i) > result[0]) {
                result[0] = list.get(j) - list.get(i);
            }
        });
    });
    return result[0];
}

Здесь я не могу использовать оператор break в потоках Java, поэтому я использовал оператор return, но он все еще выполняет внутренний цикл, так как он не прерывает его, производительность не улучшается.

Ответы [ 3 ]

10 голосов
/ 16 июня 2019

Если я понимаю ваш код, вы пытаетесь найти максимальную попарную разницу между любыми двумя элементами в списке ввода. Вы можете сделать это с IntSummaryStatistics:

public static int getMaxValue(List<Integer> list) {
    IntSummaryStatistics stats = list.stream()
        .mapToInt(Integer::intValue)
        .summaryStatistics();
    return stats.getMax() - stats.getMin();
}

Это операция O (n) с O (1) вспомогательной памятью. По-прежнему нет необходимости в операции O (n²). В конечном счете, преждевременное прерывание цикла - это оптимизация, но не очень эффективная - поиск подхода с более низкой асимптотической стоимостью всегда будет более эффективным, чем просто раннее прерывание цикла.

0 голосов
/ 16 июня 2019

Поток Java предлагает специальную функциональность для этого варианта использования, которая называется findFirst, она прекратит итерацию по коллекции и немедленно вернется.Отметьте это https://www.google.ae/amp/s/www.geeksforgeeks.org/stream-findfirst-java-examples/amp/

Более того, вы можете применить свое условие теста с помощью фильтра, вы будете использовать фильтр, чтобы проверить, а FindFirst - остановить.Это в общем то, что вы просили.

0 голосов
/ 16 июня 2019

Если вы хотите найти максимальное значение, вы можете просто сделать:

list.stream()
     .mapToInt(Integer::intValue)
     .max();

Он вернет OptionalInt, который будет пустым из вашего списка пуст.

В противном случае не уверены, чего хотите достичь с помощью своего кода ...

ОБНОВЛЕНИЕ После уточнения из оп.

Создайте небольшой класс с именем MinMax, в котором хранятся min и max, например:

public class MinMax {
  private final int min;
  private final int max;

  private MinMax(int min, int max) {
    this.min = min;
    this.max = max;
  }

  public int getDifference() {
    return this.max - this.min;
  }

  public MinMax accept(int element) {
    int newMin = element < min ? element : min;
    int newMax = element > max ? element : max;

    if (newMin != min || newMax != max) {
      return new MinMax(newMin, newMax);
    } else {
      return this;
    }
  }

  public static MinMax seed() {
    return new MinMax(Integer.MAX_VALUE, Integer.MIN_VALUE);
  }
}

Этот новый класс заботится о том, чтобы отслеживать как минимум, так и максимум. Теперь вы можете сделать что-то вроде:

int result = list.stream() 
                 .reduce(MinMax.seed(), MinMax::accept())
                 .getDifference();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...