LoginSignup
1
2

More than 3 years have passed since last update.

【Java】IntStreamで要素を逆順にソートする

Last updated at Posted at 2019-07-13

はじめに

こちらの記事にも書いている、IntStream.range()とIntStream.rangeClosed()は、指定した範囲の連続する値を得る際に非常に便利です。

しかし、これらのメソッドで得られたIntStreamは、sortedメソッドだけでは逆順にできません。

例えば以下のコードの場合、sortedメソッドの引数にComparator.reverseOrder()をとることが出来ないため、コンパイルエラーとなってしまいます。
IntStreamクラスのsortedメソッドは、引数を持たないメソッドとして定義されています。

    static void reverse() {
        IntStream.rangeClosed(1, 10)                        // IntStreamの生成
            .sorted(Comparator.reverseOrder())              // 中間操作
            .forEach(num -> System.out.println(num));       // 終端処理
    }

解決策1:boxedメソッドの利用

中間処理としてboxedメソッドを入れて、IntStreamをStream<Integer>に変換することで、sortedメソッドだけで簡単に逆順にすることができました。

Streamクラスのsortedメソッドは、Comparatorを引数にとることができます。

    static void reverse() {
        IntStream.rangeClosed(1, 10)                        // IntStreamの生成
            .boxed()                                        // ★追加した中間操作(IntStream->Stream<Integer>)
            .sorted(Comparator.reverseOrder())              // 中間操作
            .forEach(num -> System.out.println(num));       // 終端処理
    }

解決策2:IntStreamの使用を諦める

IntStreamを使わずにStream(Stream<Integer>)を使えば、この問題を回避することができます。

その代わり、IntStream.range()とやIntStream.rangeClosed()などは使えなくなってしまいます...

    static void reverse2() {
        Integer[] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        Stream<Integer> stream = Arrays.stream(values);
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

        Arrays.stream(values)                                // streamの生成
            .sorted(Comparator.reverseOrder())               // 中間操作
            .forEach(num -> System.out.println(num));        // 終端処理
    }

    /**
     * @k73i55no5さんによる改善版。listを介さずに直接配列からstreamに変換している。
     */
    static void reverse3() {
        Integer[] values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        Arrays.stream(values)                               // streamの生成
            .sorted(Comparator.reverseOrder())              // 中間操作
            .forEach(num -> System.out.println(num));       // 終端処理
    }

解決策3:符号を変換してからソートする

@swordoneさんからコメントで教えて頂いた方法で、「プラスマイナスの符号を変換して並べ替えた後、再び符号を元に戻す」というものです。

こちらでは未確認ですが、この方法を使うには幾つかの制約があるようです。
コメントでは「ネタ」と言われていますが、全く想定していない方向からボールが飛んできたように感じるほど驚きました。

    static void reverse4() {
        IntStream.rangeClosed(1, 10)                         // streamの生成
            .map(i -> -i)                                    // 中間操作(正の数->負の数)
            .sorted()                                        // 中間操作
            .map(i -> -i)                                    // 中間操作(負の数->正の数)
            .forEach(num -> System.out.println(num));        // 終端処理
    }

まとめ

  • 「IntStreamをStream<Integer>に変換する」という方法で解決できるとは思いませんでした。
    • そもそも、IntStreamとStream<Integer>の違いを全く理解していなかったです...
  • 解決策2は単なる逃げですが、絶対にIntStreamを使わなければダメということでなければ、これで良いのかもしれません。
  • Java8のStream APIは苦手(というより使う機会がない)なので、少しでも触れる機会を増やしていきたいです。
    • @LouiS0616さんのコメント(※mapメソッドを使う方法)については、もう少し勉強してから追記したいと思います。
1
2
35

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2