web-dev-qa-db-ja.com

Java 8 map操作から空の要素を返す

Java 8 stream what 最良の方法を使用してList<Integer>入力整数の出力がない場合

単にnullを返しますか?しかし今、私の出力リストのサイズは私の入力サイズよりも小さくなります...

    List<Integer> input = Arrays.asList(0,1,2,3);
    List<Integer> output = input.stream()
                                .map(i -> { 
                                    Integer out = crazyFunction(i);
                                    if(out == null || out.equals(0))
                                        return null;
                                    return Optional.of(out);
                                    })
                                .collect(Collectors.toList());
25
Martin Magakian

なぜあなた(そしてすべての答え)がそんなに複雑にしているのかわかりません。マッピング操作とフィルター操作があります。したがって、最も簡単な方法は、これらの操作を次々に適用することです。また、メソッドが既にOptionalを返さない限り、Optionalを処理する必要はありません。

input.stream().map(i -> crazyFunction(i))
              .filter(out -> out!=null && !out.equals(0))
              .collect(Collectors.toList());

に簡略化されることがあります

input.stream().map(context::crazyFunction)
              .filter(out -> out!=null && !out.equals(0))
              .collect(Collectors.toList());

しかし、どの種類のListを生成するかについて、より理論的な質問があるようです。1つは、値がない場合のプレースホルダーを使用するもの、もう1つは入力リストとは異なるサイズを使用するものです。

簡単な答えは:リストを生成しないです。 Listはそれ自体が目的ではないため、どのようなoperationこのリスト(またはその内容)が必要かを考慮し、ストリームの端末操作として操作権を適用する必要があります。 。次に、存在しない値を除外するか、特別な値で表すか(および必要な値)を操作で指定するので、答えが得られます。

異なる操作に対して異なる答えになるかもしれません…

48
Holger

map呼び出しをflatMapに置き換えます。 map操作は、入力値ごとに1つの出力値を生成しますが、flatMap操作は、入力値ごとに任意の数の出力値を生成します(ゼロを含む)。

最も簡単な方法は、おそらく次のようにチェックを置き換えることです。

List<Integer> output = input.stream()
                            .flatMap(i -> { 
                                Integer out = crazyFunction(i);
                                if (out == null || out.equals(0))
                                    return Stream.empty();
                                else
                                    return Stream.of(out);
                                })
                            .collect(Collectors.toList());

さらにリファクタリングすると、crazyFunction(おそらくOptional)を返すようにOptionalIntを変更できます。 mapから呼び出すと、結果はStream<OptionalInt>。次に、空のオプションを削除するために、そのストリームをflatMapする必要があります。

List<Integer> output = input.stream()
    .map(this::crazyFunctionReturningOptionalInt)
    .flatMap(o -> o.isPresent() ? Stream.of(o.getAsInt()) : Stream.empty())
    .collect(toList());

flatMapの結果はStream<Integer>intsを囲みますが、Listに送信するので問題ありません。 intの値をListにボックス化しない場合は、Stream<OptionalInt>IntStreamに、次を使用して:

flatMapToInt(o -> o.isPresent() ? IntStream.of(o.getAsInt()) : IntStream.empty())

オプションのストリームの処理の詳細については、 この質問とその回答 を参照してください。

30
Stuart Marks

@Martin Magakianの答えのより単純なバリアント:

List<Integer> input = Arrays.asList(0,1,2,3);
List<Optional<Integer>> output =
  input.stream()
    .map(i -> crazyFunction(i)) // you can also use a method reference here
    .map(Optional::ofNullable) // returns empty optional
                               // if original value is null
    .map(optional -> optional.filter(out -> !out.equals(0))) // return empty optional
                                                           // if captured value is zero
    .collect(Collectors.toList())
;

List<Integer> outputClean =
  output.stream()
    .filter(Optional::isPresent)
    .map(Optional::get)
    .collect(Collectors.toList())
;
2
srborlongan

出力を オプション にラップできます。この値には、null以外の値が含まれる場合と含まれない場合があります。
出力あり:return Optional.of(out);
出力なし:return Optional.<Integer>empty();

配列にはnull値を含めることができないため、オプションにラップする必要があります。

_    List<Integer> input = Arrays.asList(0,1,2,3);
    List<Option<Integer>> output = input.stream()
                                .map(i -> { 
                                    Integer out = crazyFunction(i);
                                    if(out == null || out.equals(0))
                                        return Optional.<Integer>empty();
                                    return Optional.of(out);
                                    })
                                .collect(Collectors.toList());
_

これにより、input.size() == output.size()が確認されます。

後で、次を使用して空のオプションを除外できます。

_    List<Integer> outputClean = output.stream()
                                   .filter(Optional::isPresent)
                                   .map(i -> {
                                           return i.get();
                                        })
                                   .collect(Collectors.toList());
_
1
Martin Magakian