【问题标题】:Using nested for loops in Java 8在 Java 8 中使用嵌套的 for 循环
【发布时间】:2019-06-16 14:08:10
【问题描述】:

我在下面的代码中使用了嵌套的 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];
}

这里我不能在 java 流中使用 break 语句,所以我使用了 return 语句,但它仍然运行内部循环,因为它不会破坏它,性能没有提高。

【问题讨论】:

  • 在您的原始代码中,break 不会停止外循环。不确定您认为它在做什么,但它可能没有按照您的想法做。
  • 为什么要使用流?听起来简单的 for 循环版本可以满足您的需求,那么为什么要更改它呢?
  • 我正试图准确了解您的循环在做什么。如果你只是想在列表中找到最大值,你可以做list.stream().max()。您不需要 O(n²) 算法。
  • @jbx,我说的是只打破内部循环,而不是外部循环。 I have some condition that breaks the inner for loop
  • @DanielPryden,我只是想看看在这种情况下如何使用流进行学习。

标签: java java-8


【解决方案1】:

如果我理解您的代码,您将尝试找出输入列表中任意两个元素之间的最大成对差异。你可以通过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²) 操作。归根结底,提早跳出循环是一种优化,但不是很有效——找到一种渐近成本较低的方法总是比仅仅提早跳出循环更有效。

【讨论】:

  • 我有一个不同的问题,假设输入元素已排序,现在我想查找其差异为某个值的元素的计数,例如k 即如果list.get(j) - list.get(i) == k 然后count++,@ 987654327@。在这种情况下,我如何在这里使用流。你能建议一下吗?
  • 我在这里添加了一个新问题,添加了更多详细信息 - stackoverflow.com/questions/56619896/…
【解决方案2】:

Java 流为此用例提供了一个特殊功能,即 findFirst,它将停止对集合的迭代并立即返回。检查这个 https://www.google.ae/amp/s/www.geeksforgeeks.org/stream-findfirst-java-examples/amp/

此外,您可以使用过滤器应用您的测试条件,您将使用过滤器进行检查并使用 findFirst 停止。这通常是为了满足您的要求。

【讨论】:

    【解决方案3】:

    如果您的意图是找到最大值,您可以这样做:

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

    它会返回一个OptionalInt,这将是你的空列表是空的。

    否则不确定你想用你的代码实现什么......

    更新经过 Op. 的澄清

    创建一个名为MinMax 的小类,其中存储minmax,例如:

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

    【讨论】:

    • 逻辑是关于元素之间的最大差异。不是求最大元素。
    猜你喜欢
    • 1970-01-01
    • 2020-08-09
    • 1970-01-01
    • 2015-08-03
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    • 2020-05-19
    相关资源
    最近更新 更多