1. ホーム
  2. java

[解決済み] Java 8 ストリーム逆順

2022-04-21 15:50:09

質問

一般的な質問です。ストリームを逆引きする適切な方法は何ですか?そのストリームがどのような種類の要素から構成されているのか分からないと仮定して、どのようなストリームでもリバースする一般的な方法は何でしょうか?

具体的な質問です。

IntStream は、特定の範囲の整数を生成するための range メソッドを提供します。 IntStream.range(-range, 0) しかし、それを逆にして、範囲を 0 から負に切り替えてもうまくいきません。 Integer::compare

List<Integer> list = Arrays.asList(1,2,3,4);
list.stream().sorted(Integer::compare).forEach(System.out::println);

IntStream このようなコンパイラーエラーが発生します。

Error:(191, 0) ajc: メソッド sorted() 型内の IntStream は引数には適用されません ( Integer::compare )

何が足りないのでしょうか?

どのように解決するのですか?

リバース生成の具体的な質問については IntStream は、次のようなものを試してみてください。

static IntStream revRange(int from, int to) {
    return IntStream.range(from, to)
                    .map(i -> to - i + from - 1);
}

これにより、箱詰めや並べ替えを回避することができます。

あらゆる型のストリームをどのように反転させるかという一般的な質問に対しては、私は"適切な方法があるかどうかは知りません。私が思いつく方法は2つあります。どちらもストリームの要素を保存することになります。要素を保存せずにストリームを逆行させる方法は知りません。

この最初の方法は、要素を配列に格納し、それを逆順にストリームに読み出すものです。ストリーム要素の実行時型が分からないので、配列を適切に型付けできず、チェックなしのキャストが必要なことに注意してください。

@SuppressWarnings("unchecked")
static <T> Stream<T> reverse(Stream<T> input) {
    Object[] temp = input.toArray();
    return (Stream<T>) IntStream.range(0, temp.length)
                                .mapToObj(i -> temp[temp.length - i - 1]);
}

もう一つの技法は、コレクターを使ってアイテムを逆順のリストに蓄積するものである。これは、多くの挿入を ArrayList オブジェクトのコピーも多くなります。

Stream<T> input = ... ;
List<T> output =
    input.collect(ArrayList::new,
                  (list, e) -> list.add(0, e),
                  (list1, list2) -> list1.addAll(0, list2));

ある種のカスタマイズされたデータ構造を使って、より効率的な反転コレクタを書くことは可能でしょう。

更新日 2016-01-29

この質問は最近少し注目されているので、私は答えを更新して、前面に挿入する際の問題を解決するべきだと考えています。 ArrayList . これは要素数が多いと恐ろしく非効率で、O(N^2)のコピーが必要です。

を使うのが望ましい。 ArrayDeque その代わり、前方への挿入を効率的にサポートします。小さな難点は、3つのアーグを持つ Stream.collect() この場合、2番目の引数の内容を1番目の引数にマージする必要があります。 Deque . その代わりに addAll() を使って、最初のアーギュメントの内容を2番目のアーギュメントの最後に追加し、2番目のアーギュメントを返します。そのためには Collector.of() ファクトリーメソッド

完全なコードはこうです。

Deque<String> output =
    input.collect(Collector.of(
        ArrayDeque::new,
        (deq, t) -> deq.addFirst(t),
        (d1, d2) -> { d2.addAll(d1); return d2; }));

その結果は Deque ではなく List しかし、これは大した問題ではないはずで、今は逆転した順序で簡単に反復したり流したりすることができます。