Java 8ストリームの逆順


153

一般的な質問:ストリームをリバースする適切な方法は何ですか?ストリームを構成する要素のタイプがわからない場合、ストリームを逆にする一般的な方法は何ですか?

具体的な質問:

IntStream特定の範囲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私は、このコンパイラエラーを取得します

エラー:(191、0)ajc:sorted()タイプのメソッドIntStreamは引数(Integer::compare)に適用できません

ここで何が欠けていますか?


1
アンはIntStream何も持っていない.sorted(Comparator)方法を。あなたはStream<Integer>降伏する前に最初を通過し、そこで逆転しなければなりませんIntStream
fge

OK、見つけました。.boxed()を使用してから.sorted()を使用する必要があります
vach

4
IntStream.range(0, n)逆の順序で生成するには、のようにしmap(i -> n - i - 1)ます。ボクシングとソートを行う必要はありません。
スチュアートマークス

1
あなたの一般的な質問とあなたの特定の質問は、私にとって二つの完全に異なる質問のように読めます。一般的な人はストリームを逆にすることについて話し、特定の人は降順で番号を並べることについて話します。ストリームがのような順序付けられていない方法で数値を生成する場合、1, 3, 2期待される結果は何ですか?のようなリバースされたストリーム2, 3, 1またはソートされたストリームが欲しい3, 2, 1ですか?
チコドロ2014年

8
一般的にストリームをリバースすることはできません-たとえば、ストリームは無限である可能性があります。
アッシリアス14年

回答:


78

reverseの生成に関する特定の質問についてはIntStream、次のようなことを試してください:

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

これにより、ボクシングとソートが回避されます。

どのようなタイプのストリームをリバースするかという一般的な質問については、「適切な」方法があることを知りません。私が考えることができるいくつかの方法があります。どちらもストリーム要素を格納することになります。要素を保存せずにストリームを元に戻す方法がわかりません。

この最初の方法では、要素を配列に格納し、逆の順序で要素をストリームに読み取ります。ストリーム要素の実行時の型がわからないため、配列を正しく入力できず、チェックされていないキャストが必要になることに注意してください。

@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番目の引数の内容を最初の引数にマージする必要があり、で「前にすべて追加」の一括操作はありません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になりますが、今は逆の順序で簡単に反復またはストリーミングできるため、それほど問題にはなりません。


15
または:IntStream.iterate(to-1, i->i-1).limit(to-from)
Holger

2
@Holger残念ながら、そのソリューションはオーバーフローを正しく処理しません。
ブランドン

2
@Brandon Mintern:確かに、.limit(endExcl-(long)startIncl)代わりに使用する必要がありますが、このような大きなストリームの場合は、rangeベースのソリューションよりも効率がはるかに低いため、とにかくあまりお勧めしません。コメントを書いた時点では、効率の違いに気づいていませんでした。
Holger

48

エレガントなソリューション

List<Integer> list = Arrays.asList(1,2,3,4);
list.stream()
    .boxed() // Converts Intstream to Stream<Integer>
    .sorted(Collections.reverseOrder()) // Method on Stream<Integer>
    .forEach(System.out::println);

6
リストの要素は必須であるように思われるため、エレガントですが完全には機能していませんComparable...
Krzysztof Wolny

26
これは、要素を逆順にソートすることを想定しています。問題は、ストリームの順序を逆にすることです。
ディロンライアンレディング

37

ここでのソリューションの多くはをソートまたは逆転しますがIntStream、中間ストレージが不必要に必要です。スチュアートマークスのソリューションは、次の方法です。

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

オーバーフローも正しく処理し、次のテストに合格します。

@Test
public void testRevRange() {
    assertArrayEquals(revRange(0, 5).toArray(), new int[]{4, 3, 2, 1, 0});
    assertArrayEquals(revRange(-5, 0).toArray(), new int[]{-1, -2, -3, -4, -5});
    assertArrayEquals(revRange(1, 4).toArray(), new int[]{3, 2, 1});
    assertArrayEquals(revRange(0, 0).toArray(), new int[0]);
    assertArrayEquals(revRange(0, -1).toArray(), new int[0]);
    assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE).toArray(), new int[0]);
    assertArrayEquals(revRange(MAX_VALUE, MAX_VALUE).toArray(), new int[0]);
    assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE + 1).toArray(), new int[]{MIN_VALUE});
    assertArrayEquals(revRange(MAX_VALUE - 1, MAX_VALUE).toArray(), new int[]{MAX_VALUE - 1});
}

素晴らしくてシンプル。これはいくつかのオープンソースユーティリティからのものですか?(エストリームのもの)またはあなたのコードの一部?
VACH

ありがとう!残念ながら、Estreams名前を漏らすつもりはありませんでした(投稿から削除します)。これは、java.util.stream.Streamstaticメソッドを補足するために使用する、社内のユーティリティクラスの1つです。
ブランドン、

3
わかりました…「素晴らしくてシンプル」…このソリューションで対応できるケースはありますか。スチュアートマークスのさらにシンプルなソリューションでは、1年半以上前には対応していませんでしたか。
Holger

上記のテスト方法で彼のソリューションをテストしました。それは通過します。私は彼のようにそれを受け入れるのではなく、不必要にオーバーフローを避けていました。私は彼の方が優れていることに同意します。それを反映するように編集します。
ブランドン

1
@vach、StreamExステップを指定して使用できます:IntStreamEx.rangeClosed(from-1, to, -1)
Tagir Valeev '29

34

一般的な質問:

ストリームは要素を格納しません。

そのため、要素を中間コレクションに格納しないと、要素を逆の順序で反復することはできません。

Stream.of("1", "2", "20", "3")
      .collect(Collectors.toCollection(ArrayDeque::new)) // or LinkedList
      .descendingIterator()
      .forEachRemaining(System.out::println);

更新:LinkedListをArrayDequeに変更(より良い)詳細はこちらをご覧ください

プリント:

3

20

2

1

ちなみに、sortメソッドを使用すると、逆順ではなくソートされるため正しくありません(ストリームに順序付けられていない要素がある場合)

特定の質問:

私はこれがシンプルで簡単で直感的であることを発見しました(@Holger コメントをコピーしまし

IntStream.iterate(to - 1, i -> i - 1).limit(to - from)

3
以下のようないくつかのストリームの操作、sortedおよびdistinct実際の中間結果を格納します。これに関するいくつかの情報については、パッケージAPIドキュメントを参照してください。
Lii

@Lii No storage同じページで見ます。それが保存されていても、そのストレージにアクセスすることはできません(そのため、No storage私は推測します)
Venkata Raju

いい答えだ。しかし、余分なスペースが使用されるため、非常に大規模なコレクションでプログラマーがアプローチを使用することは、あまり良い考えではありません。
Manu Manjunath

わかりやすさの観点からソリューションのシンプルさを気に入って、既存のデータ構造に既存のメソッドを活用します...以前のマップ実装のソリューションは理解するのが難しいですが、Manuが正しいことは確かです。大規模なコレクションの場合、これは使用しません。直感的で、上のマップを選択します。
Beezer、

これは、ここで数少ない正解の1つです。他のほとんどのものは実際にはストリームを逆転させず、何らかの形でそれを回避しようとします(通常、最初に逆転する必要のない特定の状況のセットでのみ機能します)。メモリに収まらないストリームをリバースしようとすると、とにかく間違っています。それをDBにダンプし、通常のSQLを使用してリバースストリームを取得します。
キュービック

19

外部ライブラリなし...

import java.util.List;
import java.util.Collections;
import java.util.stream.Collector;

public class MyCollectors {

    public static <T> Collector<T, ?, List<T>> toListReversed() {
        return Collectors.collectingAndThen(Collectors.toList(), l -> {
            Collections.reverse(l);
            return l;
        });
    }

}

15

実装されている場合Comparable<T>(例:IntegerStringDate)、あなたが使用してそれを行うことができますComparator.reverseOrder()

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

6
これはストリームを逆転しません。ストリームを逆順にソートします。あなたが持っていたのであればStream.of(1,3,2)、結果は次のようになりStream.of(3,2,1)、NOTStream.of(2,3,1)
wilmol

12

逆の順序で要素を収集する独自のコレクターを定義できます。

public static <T> Collector<T, List<T>, List<T>> inReverse() {
    return Collector.of(
        ArrayList::new,
        (l, t) -> l.add(t),
        (l, r) -> {l.addAll(r); return l;},
        Lists::<T>reverse);
}

そしてそれを次のように使用します:

stream.collect(inReverse()).forEach(t -> ...)

(リストの最後に)アイテムを効率的に挿入するためにArrayListを順方向に使用し、Guava Lists.reverseを使用して、別のコピーを作成せずにリストの反転表示を効率的に提供します。

カスタムコレクターのテストケースは次のとおりです。

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

import org.hamcrest.Matchers;
import org.junit.Test;

import com.google.common.collect.Lists;

public class TestReverseCollector {
    private final Object t1 = new Object();
    private final Object t2 = new Object();
    private final Object t3 = new Object();
    private final Object t4 = new Object();

    private final Collector<Object, List<Object>, List<Object>> inReverse = inReverse();
    private final Supplier<List<Object>> supplier = inReverse.supplier();
    private final BiConsumer<List<Object>, Object> accumulator = inReverse.accumulator();
    private final Function<List<Object>, List<Object>> finisher = inReverse.finisher();
    private final BinaryOperator<List<Object>> combiner = inReverse.combiner();

    @Test public void associative() {
        final List<Object> a1 = supplier.get();
        accumulator.accept(a1, t1);
        accumulator.accept(a1, t2);
        final List<Object> r1 = finisher.apply(a1);

        final List<Object> a2 = supplier.get();
        accumulator.accept(a2, t1);
        final List<Object> a3 = supplier.get();
        accumulator.accept(a3, t2);
        final List<Object> r2 = finisher.apply(combiner.apply(a2, a3));

        assertThat(r1, Matchers.equalTo(r2));
    }

    @Test public void identity() {
        final List<Object> a1 = supplier.get();
        accumulator.accept(a1, t1);
        accumulator.accept(a1, t2);
        final List<Object> r1 = finisher.apply(a1);

        final List<Object> a2 = supplier.get();
        accumulator.accept(a2, t1);
        accumulator.accept(a2, t2);
        final List<Object> r2 = finisher.apply(combiner.apply(a2, supplier.get()));

        assertThat(r1, equalTo(r2));
    }

    @Test public void reversing() throws Exception {
        final List<Object> a2 = supplier.get();
        accumulator.accept(a2, t1);
        accumulator.accept(a2, t2);

        final List<Object> a3 = supplier.get();
        accumulator.accept(a3, t3);
        accumulator.accept(a3, t4);

        final List<Object> r2 = finisher.apply(combiner.apply(a2, a3));

        assertThat(r2, contains(t4, t3, t2, t1));
    }

    public static <T> Collector<T, List<T>, List<T>> inReverse() {
        return Collector.of(
            ArrayList::new,
            (l, t) -> l.add(t),
            (l, r) -> {l.addAll(r); return l;},
            Lists::<T>reverse);
    }
}

9

cyclops-react StreamUtilsには、リバースStreamメソッド(javadoc)があります。

  StreamUtils.reverse(Stream.of("1", "2", "20", "3"))
             .forEach(System.out::println);

これは、ArrayListに収集してから、リストを逆方向に反復するために、どちらの方向にも反復できるListIteratorクラスを利用することで機能します。

リストがすでにある場合は、より効率的です

  StreamUtils.reversedStream(Arrays.asList("1", "2", "20", "3"))
             .forEach(System.out::println);

1
このプロジェクトについてのニースのdidntのノウハウ
VACH

1
サイクロプスには、効率的なストリーム反転のためのスプリッターも付属しています(現在は範囲、配列、リスト用)。SequenceM.of、SequenceM.range、またはSequenceM.fromListを使用してCyclops SequenceM Stream拡張を作成すると、効率的に可逆スプリッターが自動的に利用されます。
John McClean

6

jOOλの使用を勧めします。これは、Java 8ストリームとラムダに多くの便利な機能を追加する優れたライブラリです。

その後、次のことができます。

List<Integer> list = Arrays.asList(1,2,3,4);    
Seq.seq(list).reverse().forEach(System.out::println)

そのような単純な。これはかなり軽量なライブラリであり、Java 8プロジェクトに追加する価値があります。


5

これが私が思いついた解決策です:

private static final Comparator<Integer> BY_ASCENDING_ORDER = Integer::compare;
private static final Comparator<Integer> BY_DESCENDING_ORDER = BY_ASCENDING_ORDER.reversed();

次に、これらのコンパレータを使用します。

IntStream.range(-range, 0).boxed().sorted(BY_DESCENDING_ORDER).forEach(// etc...

2
これは「特定の質問」に対する回答であり、「一般的な質問」に対する回答ではありません。
チッコドロ2014年

9
Collections.reverseOrder()Java 1.2以降に存在し、Integer… で動作します
Holger

4

このユーティリティメソッドはどうですか?

public static <T> Stream<T> getReverseStream(List<T> list) {
    final ListIterator<T> listIt = list.listIterator(list.size());
    final Iterator<T> reverseIterator = new Iterator<T>() {
        @Override
        public boolean hasNext() {
            return listIt.hasPrevious();
        }

        @Override
        public T next() {
            return listIt.previous();
        }
    };
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
            reverseIterator,
            Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
}

重複することなくすべてのケースで機能するようです。


私はこのソリューションがとても好きです。ほとんどの回答は2つのカテゴリに分かれています。(1)コレクションを逆にして.stream()する、(2)カスタムコレクターにアピールする。どちらも絶対に不要です。それ以外の場合は、JDK 8自体の深刻な言語表現の問題について証言することになります。そして、あなたの答えは反対を証明します:)
vitrums

4
List newStream = list.stream().sorted(Collections.reverseOrder()).collect(Collectors.toList());
        newStream.forEach(System.out::println);

3

最も簡単な方法(単純な収集-並列ストリームをサポート):

public static <T> Stream<T> reverse(Stream<T> stream) {
    return stream
            .collect(Collector.of(
                    () -> new ArrayDeque<T>(),
                    ArrayDeque::addFirst,
                    (q1, q2) -> { q2.addAll(q1); return q2; })
            )
            .stream();
}

高度な方法(継続的な方法で並列ストリームをサポート):

public static <T> Stream<T> reverse(Stream<T> stream) {
    Objects.requireNonNull(stream, "stream");

    class ReverseSpliterator implements Spliterator<T> {
        private Spliterator<T> spliterator;
        private final Deque<T> deque = new ArrayDeque<>();

        private ReverseSpliterator(Spliterator<T> spliterator) {
            this.spliterator = spliterator;
        }

        @Override
        @SuppressWarnings({"StatementWithEmptyBody"})
        public boolean tryAdvance(Consumer<? super T> action) {
            while(spliterator.tryAdvance(deque::addFirst));
            if(!deque.isEmpty()) {
                action.accept(deque.remove());
                return true;
            }
            return false;
        }

        @Override
        public Spliterator<T> trySplit() {
            // After traveling started the spliterator don't contain elements!
            Spliterator<T> prev = spliterator.trySplit();
            if(prev == null) {
                return null;
            }

            Spliterator<T> me = spliterator;
            spliterator = prev;
            return new ReverseSpliterator(me);
        }

        @Override
        public long estimateSize() {
            return spliterator.estimateSize();
        }

        @Override
        public int characteristics() {
            return spliterator.characteristics();
        }

        @Override
        public Comparator<? super T> getComparator() {
            Comparator<? super T> comparator = spliterator.getComparator();
            return (comparator != null) ? comparator.reversed() : null;
        }

        @Override
        public void forEachRemaining(Consumer<? super T> action) {
            // Ensure that tryAdvance is called at least once
            if(!deque.isEmpty() || tryAdvance(action)) {
                deque.forEach(action);
            }
        }
    }

    return StreamSupport.stream(new ReverseSpliterator(stream.spliterator()), stream.isParallel());
}

他のタイプのストリーム(IntStreamなど)にすばやく拡張できることに注意してください。

テスト:

// Use parallel if you wish only
revert(Stream.of("One", "Two", "Three", "Four", "Five", "Six").parallel())
    .forEachOrdered(System.out::println);

結果:

Six
Five
Four
Three
Two
One

その他の注意事項:simplest way他のストリーム操作で使用した場合、それはそれほど有用ではありません(コレクト休憩並列処理に参加)。にadvance wayはその問題はありません。たとえばSORTED、ストリームの初期特性も保持されているため、リバース後に他のストリーム操作で使用するための方法です。


2

逆の順序で要素を収集するコレクターを書くことができます:

public static <T> Collector<T, ?, Stream<T>> reversed() {
    return Collectors.collectingAndThen(Collectors.toList(), list -> {
        Collections.reverse(list);
        return list.stream();
    });
}

次のように使用します。

Stream.of(1, 2, 3, 4, 5).collect(reversed()).forEach(System.out::println);

元の答え(バグが含まれています-並列ストリームでは正しく機能しません):

汎用ストリームリバースメソッドは次のようになります。

public static <T> Stream<T> reverse(Stream<T> stream) {
    LinkedList<T> stack = new LinkedList<>();
    stream.forEach(stack::push);
    return stack.stream();
}

2

純粋にJava8ではありませんが、guavaのLists.reverse()メソッドを組み合わせて使用​​すると、簡単にこれを実現できます。

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

2

逆を生成することの特定の質問に関してIntStream

始まるJavaの9あなたは三引数バージョンを使用することができますIntStream.iterate(...)

IntStream.iterate(10, x -> x >= 0, x -> x - 1).forEach(System.out::println);

// Out: 10 9 8 7 6 5 4 3 2 1 0

どこ:

IntStream.iterate​(int seed, IntPredicate hasNext, IntUnaryOperator next);

  • seed -初期要素;
  • hasNext -ストリームがいつ終了する必要があるかを決定するために要素に適用する述語。
  • next -新しい要素を作成するために前の要素に適用される関数。

1

参考までに、同じ問題を見ていましたが、ストリーム要素の文字列値を逆の順序で結合したいと思いました。

itemList = {最後、中央、最初} =>最初、中央、最後

私は中間のコレクションを使用し始めたcollectingAndThenからcomonadArrayDequeのコレクタスチュアート・マークス私は中間コレクションと幸せではなかったものの、そして再びストリーミング

itemList.stream()
        .map(TheObject::toString)
        .collect(Collectors.collectingAndThen(Collectors.toList(),
                                              strings -> {
                                                      Collections.reverse(strings);
                                                      return strings;
                                              }))
        .stream()
        .collect(Collector.joining());

そこでCollector.of、興味深いフィニッシャーラムダを持つファクトリーを使用していたスチュアートマークスの回答を繰り返し使用しました。

itemList.stream()
        .collect(Collector.of(StringBuilder::new,
                             (sb, o) -> sb.insert(0, o),
                             (r1, r2) -> { r1.insert(0, r2); return r1; },
                             StringBuilder::toString));

この場合、ストリームは並列ではないため、コンバイナーはそれほど関係ありません。insertコードの一貫性のためにとにかく使用していますが、最初に構築された文字列ビルダーに依存するため、問題ではありません。

StringJoinerを見ましたが、insertメソッドがありません。


1

IntStreamを使用してリバースするという特定の質問に答えると、以下がうまくいきました:

IntStream.range(0, 10)
  .map(x -> x * -1)
  .sorted()
  .map(Math::abs)
  .forEach(System.out::println);

1

ArrayDequeスタック内では、StackやLinkedListよりも高速です。「push()」はDequeの前に要素を挿入します

 protected <T> Stream<T> reverse(Stream<T> stream) {
    ArrayDeque<T> stack = new ArrayDeque<>();
    stream.forEach(stack::push);
    return stack.stream();
}

1

文字列または任意の配列を逆にする

(Stream.of("abcdefghijklm 1234567".split("")).collect(Collectors.collectingAndThen(Collectors.toList(),list -> {Collections.reverse(list);return list;}))).stream().forEach(System.out::println);

分割は、区切り文字またはスペースに基づいて変更できます


1

最も簡単な解決策はList::listIteratorStream::generate

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
ListIterator<Integer> listIterator = list.listIterator(list.size());

Stream.generate(listIterator::previous)
      .limit(list.size())
      .forEach(System.out::println);

Stream.generate()無限のストリームで生成することを追加する価値があるので、ここでの呼び出しlimit()は非常に重要です。
andrebrait

0

これが私のやり方です。

新しいコレクションを作成し、それを逆反復するという考えは好きではありません。

IntStream#mapのアイデアはかなり巧妙ですが、私はIntStream#iterateメソッドを好みます。ゼロへのカウントダウンのアイデアは、反復メソッドでよりよく表現され、配列を後ろから前へ歩くという観点から理解しやすいと思うからです。

import static java.lang.Math.max;

private static final double EXACT_MATCH = 0d;

public static IntStream reverseStream(final int[] array) {
    return countdownFrom(array.length - 1).map(index -> array[index]);
}

public static DoubleStream reverseStream(final double[] array) {
    return countdownFrom(array.length - 1).mapToDouble(index -> array[index]);
}

public static <T> Stream<T> reverseStream(final T[] array) {
    return countdownFrom(array.length - 1).mapToObj(index -> array[index]);
}

public static IntStream countdownFrom(final int top) {
    return IntStream.iterate(top, t -> t - 1).limit(max(0, (long) top + 1));
}

以下は、それが機能することを証明するためのいくつかのテストです。

import static java.lang.Integer.MAX_VALUE;
import static org.junit.Assert.*;

@Test
public void testReverseStream_emptyArrayCreatesEmptyStream() {
    Assert.assertEquals(0, reverseStream(new double[0]).count());
}

@Test
public void testReverseStream_singleElementCreatesSingleElementStream() {
    Assert.assertEquals(1, reverseStream(new double[1]).count());
    final double[] singleElementArray = new double[] { 123.4 };
    assertArrayEquals(singleElementArray, reverseStream(singleElementArray).toArray(), EXACT_MATCH);
}

@Test
public void testReverseStream_multipleElementsAreStreamedInReversedOrder() {
    final double[] arr = new double[] { 1d, 2d, 3d };
    final double[] revArr = new double[] { 3d, 2d, 1d };
    Assert.assertEquals(arr.length, reverseStream(arr).count());
    Assert.assertArrayEquals(revArr, reverseStream(arr).toArray(), EXACT_MATCH);
}

@Test
public void testCountdownFrom_returnsAllElementsFromTopToZeroInReverseOrder() {
    assertArrayEquals(new int[] { 4, 3, 2, 1, 0 }, countdownFrom(4).toArray());
}

@Test
public void testCountdownFrom_countingDownStartingWithZeroOutputsTheNumberZero() {
    assertArrayEquals(new int[] { 0 }, countdownFrom(0).toArray());
}

@Test
public void testCountdownFrom_doesNotChokeOnIntegerMaxValue() {
    assertEquals(true, countdownFrom(MAX_VALUE).anyMatch(x -> x == MAX_VALUE));
}

@Test
public void testCountdownFrom_givesZeroLengthCountForNegativeValues() {
    assertArrayEquals(new int[0], countdownFrom(-1).toArray());
    assertArrayEquals(new int[0], countdownFrom(-4).toArray());
}

0

これらすべてにおいて、私が最初に行く答えはわかりません。

これは質問への直接の回答ではありませんが、問題の潜在的な解決策です。

そもそもリストを逆に作成するだけです。可能であれば、ArrayListの代わりにLinkedListを使用し、アイテムを追加するときは、addの代わりに「Push」を使用します。リストは逆の順序で作成され、何も操作しなくても正しくストリーミングされます。

これは、すでにさまざまな方法で使用されているプリミティブ配列またはリストを処理しているが、驚くほど多くのケースでうまく機能する場合には当てはまりません。


0

このメソッドは任意のストリームで機能し、Java 8に準拠しています。

Stream<Integer> myStream = Stream.of(1, 2, 3, 4, 5);
myStream.reduce(Stream.empty(),
        (Stream<Integer> a, Integer b) -> Stream.concat(Stream.of(b), a),
        (a, b) -> Stream.concat(b, a))
        .forEach(System.out::println);

-1

リストを逆にする最も一般的で最も簡単な方法は次のとおりです。

public static <T> void reverseHelper(List<T> li){

 li.stream()
.sorted((x,y)-> -1)
.collect(Collectors.toList())
.forEach(System.out::println);

    }

4
の契約に違反していComparatorます。結果として、この「トリック」がソートアルゴリズムを使用する将来のJavaバージョンで機能することを誰も保証できません。たとえば、並列ソートアルゴリズムComparatorが別の方法で使用するため、同じトリックは並列ストリームでは機能しません。順次ソートの場合、それは純粋に偶然に機能します。このソリューションを使用することは誰にもお勧めしません。
Tagir Valeev、2015年

1
また、設定しても機能しませんSystem.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
Tagir Valeev、2015年

(すなわち降順)私はそれについてだけソート順に逆の順序で物事を印刷していないと思った、そしてそれはあまりにも並列ストリームで動作します: public static <T> void reverseHelper(List<T> li){ li.parallelStream() .sorted((x,y)->-1) .collect(Collectors.toList()) .forEach(System.out::println); }
parmeshwor11

1
試してみてくださいreverseHelper(IntStream.range(0, 8193).boxed().collect(Collectors.toList()))(ただし、結果はコアの数によって異なる場合があります)。
Tagir Valeev、2015年

-1

これを行うJava 8の方法:

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

4
これは、リストを元に戻すのではなく、逆の順序でソートします。
Jochen Bedersdorfer 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.