1

I have below code where I am using nested for loops and I have some condition that breaks the inner for loop, and this improves the performance of this code.

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

Now how can I use Java 8 streams to do the same logic? I have come up with below code:

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];
}

Here I cannot use a break statement in java streams, so I have used return statement, but that still runs the inner loop, as it will not break it the performance is not improved.

forpas
  • 160,666
  • 10
  • 38
  • 76
learner
  • 6,062
  • 14
  • 79
  • 139
  • In your original code, the break does not stop the outer loop. Not sure what you think it is doing, but it probably is not doing what you think it is. – jbx Jun 16 '19 at 14:11
  • 1
    Why do you want to use streams? It sounds like the simple `for` loop version does what you want, so why change it? – Daniel Pryden Jun 16 '19 at 14:12
  • I'm trying to understand exactly what your loops are doing. If you're just trying to find the max value in the list, you can just do `list.stream().max()`. You don't need an O(n²) algorithm for that. – Daniel Pryden Jun 16 '19 at 14:15
  • @jbx, I was telling about breaking inner loop only, not the outer one. `I have some condition that breaks the inner for loop` – learner Jun 16 '19 at 14:16
  • @DanielPryden, I was just trying to see how can I uses streams in this case for learning purpose. – learner Jun 16 '19 at 14:17
  • @DanielPryden, the code is about the maximum difference between elements. – learner Jun 16 '19 at 14:18

3 Answers3

10

If I understand your code, you're trying to find the maximum pairwise difference between any two elements in the input list. You can do that with IntSummaryStatistics:

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

This is an O(n) operation, with O(1) auxiliary storage. There is still no need for an O(n²) operation. Ultimately, breaking out of a loop early is an optimization, but not a very effective one -- finding an approach with a lower asymptotic cost will always be more effective than just breaking out of a loop early.

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
  • I have a different question, suppose input elements are sorted, and now I want to find the count of elements whose difference is some value say `k` i.e if `list.get(j) - list.get(i) == k` then `count++`, `else if(list.get(j) - list.get(i) > k) break`. How can I use streams here for this case. Can you please suggest. – learner Jun 16 '19 at 14:35
  • I added more details by adding a new question here - https://stackoverflow.com/questions/56619896/using-nested-for-loops-in-java-8-to-find-out-given-difference – learner Jun 16 '19 at 14:47
0

If your intention is to find the maximum value, you could just do:

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

It will return an OptionalInt which will be empty of your list is empty.

Otherwise not sure what you want to achieve with your code...

UPDATE After clarification from the Op.

Create a small class called MinMax which stores min and max, like:

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

This new class takes care of keeping track of both minimum and maximum. Now you could do something like:

int result = list.stream() 
                 .reduce(MinMax.seed(), MinMax::accept())
                 .getDifference();
jbx
  • 21,365
  • 18
  • 90
  • 144
  • The logic is about the maximum difference between elements. It is not to find the maximum element. – learner Jun 16 '19 at 14:18
0

Java stream offers a special functionality for this use case which is findFirst, it will stop iteration over the collection and return immediately. Check this https://www.google.ae/amp/s/www.geeksforgeeks.org/stream-findfirst-java-examples/amp/

Moreover you can apply your test condition with filter, you’ll use filter to check and findFirst to stop. This is in general to do what you asked for.

Mohamed Sweelam
  • 1,109
  • 8
  • 22