ストリームから連続するペアを収集する


102

のようなストリームを考えると{ 0, 1, 2, 3, 4 }

どのようにして最もエレガントにそれを与えられた形式に変換できますか?

{ new Pair(0, 1), new Pair(1, 2), new Pair(2, 3), new Pair(3, 4) }

(もちろん、私はクラスPairを定義したと仮定します)?

編集:これは、厳密にはintやプリミティブストリームに関するものではありません。答えは、あらゆるタイプのストリームに対して一般的である必要があります。


2
FPからの用語は「パーティション」ですが、Javaで目的のセマンティクスを持つメソッドが見つかりません。述語にパーティションがあります。
Marko Topolnik 2013

1
通常、JDK 8のスプリッターは、トラバースとパーティション化を目的としています。例も考えてみます。
Olimpiu POP

list.stream().map(i -> new Pair(i, i+1));
aepurniet

2
同等の非ストリームの質問については、stackoverflow.com
questions / 17453022 /…を

ちなみに、一部の人々はどちらかの実装をMap.EntryPairクラスとして使用しています。(確かに、ハックだと考える人もいるかもしれませんが、組み込みクラスを使用すると便利です。)
Basil Bourque

回答:


33

標準ストリームを拡張するMy StreamExライブラリは、pairMapすべてのストリームタイプのメソッドを提供します。プリミティブストリームの場合、ストリームタイプは変更されませんが、いくつかの計算に使用できます。最も一般的な使用法は、差異の計算です。

int[] pairwiseDiffs = IntStreamEx.of(input).pairMap((a, b) -> (b-a)).toArray();

オブジェクトストリームの場合、他のオブジェクトタイプを作成できます。私のライブラリは、ユーザーに表示されるような新しいデータ構造を提供していませんPair(これはライブラリの概念の一部です)。ただし、独自のPairクラスがあり、それを使用したい場合は、以下を実行できます。

Stream<Pair> pairs = IntStreamEx.of(input).boxed().pairMap(Pair::new);

または、すでにいくつかある場合Stream

Stream<Pair> pairs = StreamEx.of(stream).pairMap(Pair::new);

この機能は、カスタムスプリッターを使用して実装されます。オーバーヘッドがかなり低く、適切に並列化できます。もちろん、他の多くのソリューションのようなランダムアクセスリスト/アレイだけでなく、あらゆるストリームソースで機能します。多くのテストでそれは本当によく機能します。ここだ我々は(参照異なるアプローチを使用して、より大きな値を前のすべての入力値を見つけるJMHベンチマークこの質問は)。


ありがとうございました!このライブラリを研究すればするほど、愛するようになります。ようやくストリームを使い始めるかもしれません。(StreamExインプリメントIterable!Hurrah!)
Aleksandr Dubinsky

あなたの答えは、100%完全なものにするには、ラップする方法を示すことができたStreamStreamEx
Aleksandr Dubinsky

3
@AleksandrDubinsky:だけを使用してくださいStreamEx.of(stream)Collection、配列Readerなどからストリームを作成する他の便利な静的メソッドがあります。回答を編集しました。
Tagir Valeev

@TagirValeevはpairMapシーケンシャルストリームで注文されますか?実際にはforPairsOrdered()が欲しいのですが、そのようなメソッドがないので、どうにかシミュレーションできますか?stream.ordered().forPairs()またはstream().pairMap().forEachOrdered()
Askar Kalykov、2015年

1
@AskarKalykov、これpairMapは、干渉のないステートレスマッパー関数を使用した中間操作であり、simpleの場合と同じように順序付けが指定されていませんmapforPairs仕様によって順不同れるが、順不同の操作が事実上のシーケンシャルストリームに対して順序付けられます。より多くのコンテキストを提供するために、元の問題を個別のスタックオーバーフローの質問として定式化するとよいでしょう。
Tagir Valeev、2015年

74

Java 8ストリームライブラリは主に、並列処理のためにストリームを小さなチャンクに分割することを目的としているため、ステートフルパイプラインステージは非常に制限されており、現在のストリーム要素のインデックスの取得や隣接するストリーム要素へのアクセスなどの処理はサポートされていません。

もちろん、これらの問題を解決する一般的な方法は、いくつかの制限がありますが、インデックスでストリームを駆動し、要素を取得できるArrayListなどのランダムアクセスデータ構造で値を処理することに依存しています。値がにある場合、arrayList次のようなことを実行して、要求に応じてペアを生成できます。

    IntStream.range(1, arrayList.size())
             .mapToObj(i -> new Pair(arrayList.get(i-1), arrayList.get(i)))
             .forEach(System.out::println);

もちろん、入力が無限ストリームであってはならないという制限があります。ただし、このパイプラインは並行して実行できます。


5
「入力を無限ストリームにすることはできません。」実際には、入力をストリームにすることはできません。入力(arrayList)は実際にはコレクションです。そのため、答えとしてマークしませんでした。(しかし、ゴールドバッジおめでとうございます!)
Aleksandr Dubinsky

16

これはエレガントではなく、ハックなソリューションですが、無限のストリームで機能します

Stream<Pair> pairStream = Stream.iterate(0, (i) -> i + 1).map( // natural numbers
    new Function<Integer, Pair>() {
        Integer previous;

        @Override
        public Pair apply(Integer integer) {
            Pair pair = null;
            if (previous != null) pair = new Pair(previous, integer);
            previous = integer;
            return pair;
        }
    }).skip(1); // drop first null

これで、ストリームを必要な長さに制限できます

pairStream.limit(1_000_000).forEach(i -> System.out.println(i));

PS私はclojureのようなより良い解決策があることを望みます(partition 2 1 stream)


6
匿名クラスはラムダの代わりに役立つ場合があることを指摘した功績。
Aleksandr Dubinsky

2
@aepurniet正しく動作しないと思います。parallelStream文書によると、「正しい動作を維持するには、これらの動作パラメータは干渉しない必要があり、ほとんどの場合ステートレスである必要があります」
mishadoff

14
これはストリームフレームワークの設計に完全に反し、無名関数はステートレスではないため、マップAPIの規約に直接違反します。これを並列ストリームとより多くのデータで実行してみて、ストリームフレームワークがより多くの作業スレッドを作成するようにします。結果が表示されます。まれなランダムな「エラー」を再現することはほとんど不可能で、十分なデータ(本番環境にあるか?)になるまで検出が困難です。これは悲惨なことです。
マリオロッシ

4
@AleksandrDubinsky並列化可能な制限/スキップについて間違っています。JDKで提供される実装は、実際には並行して機能します。操作はエンカウンターの順序に関連付けられているため、並列化によって常にパフォーマンスが向上するわけではありませんが、高Qの状況では可能です。
Brian Goetz 2016年

4
@AleksandrDubinsky不正解です。ストリームが順序付けられていない場合、ランダム要素をスキップする場合があります(エンカウンター順序が定義されていないため、論理的に「最初」または「n番目」の要素はなく、要素だけです)。並行して作業します。ストリームが順序付けされている場合、抽出する並列処理は少なくなりますが、それでも並列処理は行われます。
Brian Goetz、2016年

15

私は、元のスプリッターからすべてのn要素Tを取得して生成するスプリッターラッパーを実装しましたList<T>

public class ConsecutiveSpliterator<T> implements Spliterator<List<T>> {

    private final Spliterator<T> wrappedSpliterator;

    private final int n;

    private final Deque<T> deque;

    private final Consumer<T> dequeConsumer;

    public ConsecutiveSpliterator(Spliterator<T> wrappedSpliterator, int n) {
        this.wrappedSpliterator = wrappedSpliterator;
        this.n = n;
        this.deque = new ArrayDeque<>();
        this.dequeConsumer = deque::addLast;
    }

    @Override
    public boolean tryAdvance(Consumer<? super List<T>> action) {
        deque.pollFirst();
        fillDeque();
        if (deque.size() == n) {
            List<T> list = new ArrayList<>(deque);
            action.accept(list);
            return true;
        } else {
            return false;
        }
    }

    private void fillDeque() {
        while (deque.size() < n && wrappedSpliterator.tryAdvance(dequeConsumer))
            ;
    }

    @Override
    public Spliterator<List<T>> trySplit() {
        return null;
    }

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

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

次のメソッドを使用して、連続ストリームを作成できます。

public <E> Stream<List<E>> consecutiveStream(Stream<E> stream, int n) {
    Spliterator<E> spliterator = stream.spliterator();
    Spliterator<List<E>> wrapper = new ConsecutiveSpliterator<>(spliterator, n);
    return StreamSupport.stream(wrapper, false);
}

使用例:

consecutiveStream(Stream.of(0, 1, 2, 3, 4, 5), 2)
    .map(list -> new Pair(list.get(0), list.get(1)))
    .forEach(System.out::println);

すべての要素を2回繰り返しますか?
Aleksandr Dubinsky

いいえ。List<E>要素を含む新しいストリームを作成します。各リストにはn、元のストリームからの連続した要素が含まれています。自分で確認してください;)
TomekRękawek2013

すべての要素(最初と最後を除く)が繰り返されるように答えを変更できますか?
Aleksandr Dubinsky

4
+1これは良い作業であり、パーティションサイズに加えて任意のステップサイズに一般化する必要があると思います。(partition size step)関数には多くのニーズがあり、これはそれを取得するための最良の方法についてです。
Marko Topolnik 14

3
ではなくArrayDeque、パフォーマンスのために使用することを検討してくださいLinkedList
Marko Topolnik 14

14

Stream.reduce()メソッドを使用してこれを行うことができます(このテクニックを使用した他の回答は見たことがありません)。

public static <T> List<Pair<T, T>> consecutive(List<T> list) {
    List<Pair<T, T>> pairs = new LinkedList<>();
    list.stream().reduce((a, b) -> {
        pairs.add(new Pair<>(a, b));
        return b;
    });
    return pairs;
}

1
(1,2)(3,4)ではなく(1,2)(2,3)を返します。また、それが順番に適用されるかどうかもわかりません(確かにその保証はありません)。
Aleksandr Dubinsky 2017年

1
質問を確認してください、それは意図された動作です@Aleksandr Dubinsky
SamTebbs33

3
ああ、はい、ごめんなさい。そして考えて、私はそれを書きました。
Aleksandr Dubinsky 2017年


6

これは、slidingオペレーターを使用して、cyclops-react(このライブラリーに寄稿)で行うことができます。

  LazyFutureStream.of( 0, 1, 2, 3, 4 )
                  .sliding(2)
                  .map(Pair::new);

または

   ReactiveSeq.of( 0, 1, 2, 3, 4 )
                  .sliding(2)
                  .map(Pair::new);

Pairコンストラクターが2つの要素を持つコレクションを受け入れることができると仮定します。

4でグループ化し、2でインクリメントする場合もサポートされます。

     ReactiveSeq.rangeLong( 0L,Long.MAX_VALUE)
                .sliding(4,2)
                .forEach(System.out::println);

java.util.stream.Streamのスライディングビューを作成するための同等の静的メソッドも、cyclops-streams StreamUtilsクラスで提供されます。

       StreamUtils.sliding(Stream.of(1,2,3,4),2)
                  .map(Pair::new);

注:-シングルスレッド操作の場合、ReactiveSeqがより適切です。LazyFutureStreamはReactiveSeqを拡張しますが、主に同時/並列使用向けです(先物ストリームです)。

LazyFutureStreamは、ReactiveSeqを拡張します。これは、素晴らしいjOOλ(java.util.stream.Streamを拡張)からSeqを拡張します。そのため、Lukasのプレゼントのソリューションは、どちらのStreamタイプでも機能します。興味のある人にとって、ウィンドウ/スライディングオペレーターの主な違いは、明らかな相対的なパワー/複雑さのトレードオフであり、無限ストリームでの使用に適しています(スライディングはストリームを消費しませんが、フロー中にバッファーを消費します)。


このようにして[(0,1)(2,3)...]を取得しますが、質問は[(0,1)(1,2)...]を尋ねます。RxJavaで私の答えを参照してください...
frhack

1
あなたは正しい、私の悪い、私は質問を読み間違えました-ここではスライディング演算子が正しいものです。回答を更新します。ありがとうございます。
John McClean

4

プロトンパックライブラリは、ウィンドウfunctionnalityを提供します。PairクラスとStreamを指定すると、次のように実行できます。

Stream<Integer> st = Stream.iterate(0 , x -> x + 1);
Stream<Pair<Integer, Integer>> pairs = StreamUtils.windowed(st, 2, 1)
                                                  .map(l -> new Pair<>(l.get(0), l.get(1)))
                                                  .moreStreamOps(...);

これで、pairsストリームには次が含まれます。

(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, ...) and so on

ただし、st2回作成する必要があるようです。このライブラリは、単一のストリームを使用して問題を解決できますか?
Aleksandr Dubinsky

@AleksandrDubinsky私はそうは思わないので、現在のスプリッターで利用できます。問題github.com/poetix/protonpack/issues/9
Alexis C.

@AleksandrDubinsky windowed機能が追加されました!編集を参照してください。
Alexis C.

1
古い回答を削除して、他のユーザーが履歴ではなくソリューションを表示できるようにしてください。
Aleksandr Dubinsky 2015年

4

連続するペアを見つける

サードパーティのライブラリを使用して並列処理が不要な場合、jOOλは次のようなSQLスタイルのウィンドウ関数を提供します

System.out.println(
Seq.of(0, 1, 2, 3, 4)
   .window()
   .filter(w -> w.lead().isPresent())
   .map(w -> tuple(w.value(), w.lead().get())) // alternatively, use your new Pair() class
   .toList()
);

降伏

[(0, 1), (1, 2), (2, 3), (3, 4)]

このlead()関数は、ウィンドウからトラバーサル順序で次の値にアクセスします。

連続するトリプル/四重/ nタプルを見つける

コメントの質問は、より一般的な解決策を求めていました。ペアではなく、nタプル(またはおそらくリスト)を収集する必要があります。したがって、ここに代替アプローチがあります:

int n = 3;

System.out.println(
Seq.of(0, 1, 2, 3, 4)
   .window(0, n - 1)
   .filter(w -> w.count() == n)
   .map(w -> w.window().toList())
   .toList()
);

リストのリストを生成する

[[0, 1, 2], [1, 2, 3], [2, 3, 4]]

なしではfilter(w -> w.count() == n)、結果は

[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4], [4]]

免責事項:私はjOOλの背後にある会社で働いています


面白い。3つ以上の要素をグループ化する必要がある場合はどうなりますか?使用しw.lead().lead()ますか?
Raul Santelices 2016年

1
@RaulSantelices:tuple(w.value(), w.lead(1), w.lead(2))オプションになります。私はより一般的な解決策で回答を更新しましたlength = n
Lukas Eder

1
.window()入力ストリーム全体をいくつかの中間コレクションに収集し、そこから新しいストリームを作成する遅延操作ではないことを正しく理解していますか?
Tagir Valeev 2016年

@TagirValeev:はい、それが現在の実装です。上記のケース(Comparatorウィンドウの並べ替えにno が使用される)では、このような最適化が可能であり、将来実装される可能性があります。
Lukas Eder


2

RxJava(非常に強力なリアクティブ拡張ライブラリ)を使用できます

IntStream intStream  = IntStream.iterate(1, n -> n + 1);

Observable<List<Integer>> pairObservable = Observable.from(intStream::iterator).buffer(2,1);

pairObservable.take(10).forEach(b -> {
            b.forEach(n -> System.out.println(n));
            System.out.println();
        });

バッファ オペレータが発するが、これらのアイテムのコレクションを緩衝することを観察可能に観測その発するアイテムを変換します..


1
私が使用しObservable.zip(obs, obs.skip(1), pair->{...})、今まで!Observable.bufferステップ付きのバージョンがあることを知りませんでした(そして、私はzippython からのトリックに慣れています)。+1
Reut Sharabani

1

操作は、ストリームが解決することを意図しているものではないので、実際には、本質的にステートフルである-に「ステートレス行動」のセクションを参照してくださいjavadocは

最善のアプローチは、操作を完全にストリーミングするステートフルな動作パラメーターを回避することです

ここでの1つの解決策は、外部カウンターを通じてストリームに状態を​​導入することですが、これはシーケンシャルストリームでのみ機能します。

public static void main(String[] args) {
    Stream<String> strings = Stream.of("a", "b", "c", "c");
    AtomicReference<String> previous = new AtomicReference<>();
    List<Pair> collect = strings.map(n -> {
                            String p = previous.getAndSet(n);
                            return p == null ? null : new Pair(p, n);
                        })
                        .filter(p -> p != null)
                        .collect(toList());
    System.out.println(collect);
}


static class Pair<T> {
    private T left, right;
    Pair(T left, T right) { this.left = left; this.right = right; }
    @Override public String toString() { return "{" + left + "," + right + '}'; }
}

質問は、連続する整数を収集するだけでなく、入力ストリームの連続する要素を収集することを求めています。用語の重要な明確化:Stream!= "ラムダ"。
Aleksandr Dubinsky、2015年

AtomicIntegerをAtomicReferenceに置き換えることができます。代わりに、独自のコレクターをロールするか、次の例のような外部ライブラリーを使用します:stackoverflow.com/a/30090528/829571
assylias

私の編集を参照してください。また、ラムダ!=ストリームに関するコメントを理解しているかどうかもわかりません。匿名クラスを使用する他の答えは、状態が外部ではなく匿名クラスによって保持されることを除いて、基本的に同じことを行います...
assylias

1
うまくいきます。StreamExライブラリーはまた、良好な検索であり、それ自体で答えである可能性があります。「ストリーム!=ラムダ」に関する私のコメントは、「操作は本質的にステートフルであるため、ラムダが何を解決することを意図していないか」と述べています。「ストリーム」という言葉を使うつもりだったと思います。
Aleksandr Dubinsky

ああ、わかりました-明確にしました。
アッシリア

0

あなたの場合、最後に渡されたintを追跡するカスタムIntFunctionを記述し、それを使用して元のIntStreamをマップします。

import java.util.function.IntFunction;
import java.util.stream.IntStream;

public class PairFunction implements IntFunction<PairFunction.Pair> {

  public static class Pair {

    private final int first;
    private final int second;

    public Pair(int first, int second) {
      this.first = first;
      this.second = second;
    }

    @Override
    public String toString() {
      return "[" + first + "|" + second + "]";
    }
  }

  private int last;
  private boolean first = true;

  @Override
  public Pair apply(int value) {
    Pair pair = !first ? new Pair(last, value) : null;
    last = value;
    first = false;
    return pair;
  }

  public static void main(String[] args) {

    IntStream intStream = IntStream.of(0, 1, 2, 3, 4);
    final PairFunction pairFunction = new PairFunction();
    intStream.mapToObj(pairFunction)
        .filter(p -> p != null) // filter out the null
        .forEach(System.out::println); // display each Pair

  }

}

これの問題は、それがウィンドウからステートレスをスローすることです。
Rob

@ロブ、それで何が問題なの?
Aleksandr Dubinsky

ラムダの主要なポイントの1つは、内部のインテグレーターが作業を並列処理できるように、変更可能な状態を持たないことです。
Rob

@ロブ:ええ、あなたは正しいですが、与えられたサンプルストリームはとにかく、各アイテム(最初と最後のものを除く)がいくつかのペアの最初と2番目のアイテムとして使用されるため、並列処理を拒否します。
jpvee 2013

@jpveeええ、私はそれがあなたが考えていたことだと思いました。他のマッパーでこれを行う方法はないのでしょうか。要するに、必要なのはループインクリメンターを2ずつ増やし、ファンクターに2つの引数をとらせることと同じです。それは可能でなければなりません。
Rob

0

時系列の時間(x値)の連続する差を計算するには、streamcollect(...)方法を使用します。

final List< Long > intervals = timeSeries.data().stream()
                    .map( TimeSeries.Datum::x )
                    .collect( DifferenceCollector::new, DifferenceCollector::accept, DifferenceCollector::combine )
                    .intervals();

DifferenceCollectorは次のようになります。

public class DifferenceCollector implements LongConsumer
{
    private final List< Long > intervals = new ArrayList<>();
    private Long lastTime;

    @Override
    public void accept( final long time )
    {
        if( Objects.isNull( lastTime ) )
        {
            lastTime = time;
        }
        else
        {
            intervals.add( time - lastTime );
            lastTime = time;
        }
    }

    public void combine( final DifferenceCollector other )
    {
        intervals.addAll( other.intervals );
        lastTime = other.lastTime;
    }

    public List< Long > intervals()
    {
        return intervals;
    }
}

おそらく、必要に応じてこれを変更できます。


0

ようやく、Stream.reduceをだまして値のペアを適切に処理できる方法を見つけました。この機能を必要とするユースケースは多数ありますが、JDK 8 自然には現れません。

public static int ArithGeo(int[] arr) {
    //Geometric
    List<Integer> diffList = new ArrayList<>();
    List<Integer> divList = new ArrayList<>();
    Arrays.stream(arr).reduce((left, right) -> {
        diffList.add(right-left);
        divList.add(right/left);
        return right;
    });
    //Arithmetic
    if(diffList.stream().distinct().count() == 1) {
        return 1;
    }
    //Geometric
    if(divList.stream().distinct().count() == 1) {
        return 2;
    }
    return -1;
}

私が使用するトリックは、復帰権です。ステートメント。


1
reduceこれが機能するのに十分な保証はないと思います。
Aleksandr Dubinsky

十分な保証について詳しく知りたいと思います。詳しく説明していただけますか?たぶんグアバに代替があるかもしれません...しかし私は制約されてそれを使用することはできません。
Beezer

-1

エレガントなソリューションはzipを使用することです。何かのようなもの:

List<Integer> input = Arrays.asList(0, 1, 2, 3, 4);
Stream<Pair> pairStream = Streams.zip(input.stream(),
                                      input.stream().substream(1),
                                      (a, b) -> new Pair(a, b)
);

これはかなり簡潔でエレガントですが、入力としてリストを使用します。無限ストリームソースはこの方法では処理できません。

もう1つの(かなり厄介な)問題は、zipとStreamsクラス全体が最近APIから削除されていることです。上記のコードは、b95以前のリリースでのみ機能します。したがって、最新のJDKでは、エレガントなFPスタイルのソリューションは存在しないと思います。現時点では、何らかの方法でzipがAPIに再導入されることを期待できます。


確かに、zip削除されました。Streamsクラスの内容をすべて覚えているわけではありませんが、一部はStreamインターフェースの静的メソッドに移行しStreamSupportStream.Builderクラスとクラスもあります。
Stuart Marks

そのとおり。concatやiterateのような他のいくつかのメソッドは移動され、Streamのデフォルトメソッドになりました。残念ながら、zipはAPIから削除されました。この選択の背後にある理由(タプルの不足など)は理解していますが、それでも優れた機能でした。
ガジェット

2
@gadgetタプルは何と関係がありzipますか?どんな独創的な理由が発明されても、殺害を正当化するものではありませんzip
Aleksandr Dubinsky

@AleksandrDubinskyほとんどの場合、出力としてペア/タプルのコレクションを生成するためにzipが使用されます。彼ら、もし彼らがzipを保持ていれば、JDKの一部としてタプルも要求するだろうと主張しました。ただし、既存の機能を削除したことはありません。
ガジェット

-1

これは興味深い問題です。私のハイブリッドの試みは何か良いものですか?

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3);
    Iterator<Integer> first = list.iterator();
    first.next();
    if (first.hasNext())
        list.stream()
        .skip(1)
        .map(v -> new Pair(first.next(), v))
        .forEach(System.out::println);
}

並列処理には向いていないため、失格となる可能性があります。


質問は並列処理を要求しStreamませんでしたが、はなく、しかないと仮定しましたList。もちろん、ストリームからイテレータを引き出すこともできるので、これは有効な解決策になるかもしれません。それにもかかわらず、それは独自のアプローチです。
Aleksandr Dubinsky 2016

-1

他の人が観察したように、問題の性質上、ある程度のステートフル性が必要です。

私は同様の問題に直面しました。この問題では、本質的にOracle SQL関数LEADが必要でした。それを実装する私の試みは以下です。

/**
 * Stream that pairs each element in the stream with the next subsequent element.
 * The final pair will have only the first item, the second will be null.
 */
<T> Spliterator<Pair<T>> lead(final Stream<T> stream)
{
    final Iterator<T> input = stream.sequential().iterator();

    final Iterable<Pair<T>> iterable = () ->
    {
        return new Iterator<Pair<T>>()
        {
            Optional<T> current = getOptionalNext(input);

            @Override
            public boolean hasNext()
            {
                return current.isPresent();
            }

            @Override
            public Pair<T> next()
            {
                Optional<T> next = getOptionalNext(input);
                final Pair<T> pair = next.isPresent()
                    ? new Pair(current.get(), next.get())
                    : new Pair(current.get(), null);
                current = next;

                return pair;
            }
        };
    };

    return iterable.spliterator();
}

private <T> Optional<T> getOptionalNext(final Iterator<T> iterator)
{
    return iterator.hasNext()
        ? Optional.of(iterator.next())
        : Optional.empty();
}

-1

これを実現するには、境界キューを使用して、ストリームを流れる要素を格納します(これは、ここで詳細に説明したアイデアに基づいています)。 ストリーム内の次の要素を取得することは可能ですか?

以下の例では、最初に、ストリームを通過する要素を格納するBoundedQueueクラスのインスタンスを定義します(LinkedListを拡張したくない場合は、上記のリンクを参照して、代替のより一般的な方法を確認してください)。その後、2つの後続の要素を組み合わせてペアのインスタンスにします。

public class TwoSubsequentElems {
  public static void main(String[] args) {
    List<Integer> input = new ArrayList<Integer>(asList(0, 1, 2, 3, 4));

    class BoundedQueue<T> extends LinkedList<T> {
      public BoundedQueue<T> save(T curElem) {
        if (size() == 2) { // we need to know only two subsequent elements
          pollLast(); // remove last to keep only requested number of elements
        }

        offerFirst(curElem);

        return this;
      }

      public T getPrevious() {
        return (size() < 2) ? null : getLast();
      }

      public T getCurrent() {
        return (size() == 0) ? null : getFirst();
      }
    }

    BoundedQueue<Integer> streamHistory = new BoundedQueue<Integer>();

    final List<Pair<Integer>> answer = input.stream()
      .map(i -> streamHistory.save(i))
      .filter(e -> e.getPrevious() != null)
      .map(e -> new Pair<Integer>(e.getPrevious(), e.getCurrent()))
      .collect(Collectors.toList());

    answer.forEach(System.out::println);
  }
}

-3

@aepurnietに同意しますが、代わりにマップするにはmapToObjを使用する必要があります

range(0, 100).mapToObj((i) -> new Pair(i, i+1)).forEach(System.out::println);

1
正しい。ただし、これは整数のペアを収集するだけであり、(任意のタイプの)ストリームの要素のペアは収集しません。
Aleksandr Dubinsky、2015年

-5

ストリームのfor0から実行されるループを実行するlength-1

for(int i = 0 ; i < stream.length-1 ; i++)
{
    Pair pair = new Pair(stream[i], stream[i+1]);
    // then add your pair to an array
}

3
そして、ソリューションのラムダ部分はどこですか?
Olimpiu POP

ストリームが無限の場合はそうではありません
ミスハドオフ

@Olimpiu-ラムダをどこで入手したのですか?質問を2回読んで、見逃していないか確認しました。編集履歴も確認しました。そして、質問はそれにタグ付けされていません。
jww 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.