【问题标题】:Reverse Sort a stream反向排序流
【发布时间】:2019-05-14 20:02:59
【问题描述】:

我想对如下所示的流进行反向排序,但编译时错误为"The method sorted() in the type IntStream is not applicable for the arguments ((<no type> o1, <no type> o2) -> {})"。任何人都可以纠正这个

IntStream.range(1, 100)
         .filter(x -> x%2 != 0)
         .sorted((o1,o2) -> -o1.compareTo(o2))
         .forEach(System.out::println);

【问题讨论】:

  • 我很好奇你为什么要使用流来做这样的事情。这似乎只会增加一堆开销。

标签: java sorting java-8 java-stream


【解决方案1】:

说明

由于您使用的是IntStream,它只有一个sorted 方法的重载,这是自然顺序(这是有道理的)。

相反,将流从IntStream 装箱到Stream<Integer> 就足够了:

 IntStream.range(1, 100)
          .filter(x -> x % 2 != 0)
          .boxed()  // <--- boxed to Stream<Integer>
          .sorted((o1,o2) -> -o1.compareTo(o2)) // now we can call compareTo on Integer
          .forEach(System.out::println);

但是,正如 @Holger 在 cmets 中提到的那样:

永远不要使用像(o1,o2) -&gt; -o1.compareTo(o2) 这样的比较器函数。它 compareTo 实现返回是完全合法的 Integer.MIN_VALUE,在这种情况下,否定将失败并产生 结果不一致。一个有效的反向比较器是 (o1,o2) -> o2.compareTo(o1)

改进代码的建议。 JDK8

更好的方法是:

IntStream.range(1, 100)
         .filter(x -> x % 2 != 0)
         .boxed()
         .sorted(Comparator.reverseOrder())
         .forEachOrdered(System.out::println);

为什么?

  • 已经有一个内置的比较器来执行如上所示的逆序。
  • 如果您想保证在打印时按排序顺序查看元素,请使用forEachOrdered(大喊@Holger 总是提醒我)

或者正如@Holger 所建议的那样,它都可以简化为:

 IntStream.range(0, 50)
          .map(i -> 99-i*2)
          .forEachOrdered(System.out::println);

JDK9 变种

顺便说一句,在JDK9中,从您帖子中的代码开始,您可以先通过iterate将其简化为:

IntStream.iterate(1, i  -> i <= 99, i -> i + 2)
         .boxed()
         .sorted(Comparator.reverseOrder())
         .forEachOrdered(System.out::println);

通过这种方法,我们可以避免过滤器中间操作和以2为单位的增量。

最后你可以进一步简化它:

IntStream.iterate(99, i  -> i > 0 , i -> i - 2)
         .forEachOrdered(System.out::println);

通过这种方法,我们可以避免filterboxedsorted 等。

【讨论】:

  • 我们平时提醒的时候,千万不要使用(o1,o2) -&gt; -o1.compareTo(o2)这样的比较器功能。 compareTo 实现返回 Integer.MIN_VALUE 是完全合法的,在这种情况下,否定将失败并产生不一致的结果。一个有效的反向比较器将是(o1,o2) -&gt; o2.compareTo(o1),或者只是Comparator.reverseOrder(),正如您所展示的,这已经完成了这项工作。顺便说一句,我不会使用iterate,而是使用IntStream.range(0, 50).map(i -&gt; 99-i*2),这在很多情况下更有效。
  • @Holger 非常感谢,一如既往地学习。编辑以适应您的建议。
【解决方案2】:

如果那是您的真实代码,那么使用IntStream.iterate 并生成从990 的数字可能会更有效:

IntStream.iterate(99, i -> i - 1)
    .limit(100)
    .filter(x -> x % 2 != 0)
    .forEachOrdered(System.out::println);

【讨论】:

    【解决方案3】:

    简单的实用程序怎么样:

    private IntStream reverseSort(int from, int to) {
        return IntStream.range(from, to)
                        .filter(x -> x % 2 != 0)
                        .sorted()
                        .map(i -> to - i + from - 1);
    }
    

    致谢Stuart Marks for the reverse util

    【讨论】:

      猜你喜欢
      • 2014-03-23
      • 1970-01-01
      • 2011-02-16
      • 2022-11-28
      • 2016-12-05
      • 1970-01-01
      • 2013-12-10
      • 2017-07-20
      • 2015-06-03
      相关资源
      最近更新 更多