ストリームを2つに分割できますか? 質問する

ストリームを2つに分割できますか? 質問する

Java 8 ストリームで表されるデータ セットがあります。

Stream<T> stream = ...;

ランダムなサブセットを取得するためにフィルタリングする方法がわかります - たとえば

Random r = new Random();
PrimitiveIterator.OfInt coin = r.ints(0, 2).iterator();   
Stream<T> heads = stream.filter((x) -> (coin.nextInt() == 0));

このストリームを縮小して、たとえばデータセットの2つのランダムな半分を表す2つのリストを取得し、それをストリームに戻す方法もわかります。しかし、最初のストリームから2つのストリームを直接生成する方法はありますか?次のようなものです。

(heads, tails) = stream.[some kind of split based on filter]

ご意見をいただければ幸いです。

ベストアンサー1

コレクタこれに使用できます。

  • 2 つのカテゴリの場合は、Collectors.partitioningBy()factory を使用します。

これにより、 が作成されMap<Boolean, List>、 に基づいていずれかのリストにアイテムが配置されますPredicate

注: ストリーム全体を消費する必要があるため、これは無限のストリームでは機能しません。また、ストリームはいずれ消費されるため、このメソッドは新しいメモリ付きストリームを作成するのではなく、単にリストに配置します。出力としてストリームが必要な場合は、いつでもこれらのリストをストリームできます。

また、提供されたヘッドのみの例でも、反復子は必要ありません。

  • バイナリ分割は次のようになります。
Random r = new Random();

Map<Boolean, List<String>> groups = stream
    .collect(Collectors.partitioningBy(x -> r.nextBoolean()));

System.out.println(groups.get(false).size());
System.out.println(groups.get(true).size());
  • より多くのカテゴリについては、Collectors.groupingBy()ファクトリーを使用します。
Map<Object, List<String>> groups = stream
    .collect(Collectors.groupingBy(x -> r.nextInt(3)));
System.out.println(groups.get(0).size());
System.out.println(groups.get(1).size());
System.out.println(groups.get(2).size());

ストリームが ではなくStream、 のようなプリミティブ ストリームのいずれかである場合IntStream、この.collect(Collectors)メソッドは使用できません。コレクター ファクトリを使用せずに手動で実行する必要があります。実装は次のようになります。

[2020-04-16 以降の例 2.0]

    IntStream    intStream = IntStream.iterate(0, i -> i + 1).limit(100000).parallel();
    IntPredicate predicate = ignored -> r.nextBoolean();

    Map<Boolean, List<Integer>> groups = intStream.collect(
            () -> Map.of(false, new ArrayList<>(100000),
                         true , new ArrayList<>(100000)),
            (map, value) -> map.get(predicate.test(value)).add(value),
            (map1, map2) -> {
                map1.get(false).addAll(map2.get(false));
                map1.get(true ).addAll(map2.get(true ));
            });

この例では、ArrayListsを初期コレクションのフルサイズで初期化します(これがわかっている場合)。これにより、最悪のシナリオでもサイズ変更イベントを回避できますが、2を消費する可能性があります。いいえT スペース (N = 初期要素数、T = スレッド数)。スペースと速度をトレードオフするには、これを省略するか、1 つのパーティション内の予想される最大要素数 (通常、バランスの取れた分割の場合は N/2 をわずかに超える) などの最善の推測値を使用します。

Java 9 の方法を使用して誰かを不快にさせないように願っています。Java 8 バージョンについては、編集履歴を参照してください。

おすすめ記事