私の質問をチェックしてくれてありがとう!
複数の述語が特定の順序で適用されている Streams を使用して頭を悩ませています。
例として、次の IntPredicates を検討してください。
IntPredicate divisibleByThree = i -> i % 3 == 0;
IntPredicate divisibleByFour = i -> i % 4 == 0;
IntPredicate divisibleByFive = i -> i % 5 == 0;
IntPredicate divisibleByThreeAndFour = divisibleByThree.and(divisibleByFour);
IntPredicate divisibleByThreeAndFive = divisibleByThree.and(divisibleByFive);
IntPredicate divisibleByThreeAndFiveAndFour = divisibleByThreeAndFour.and(divisibleByFive);
//....arbitrary Number of predicates.
パート1
私が抱えている問題を「FizzBuzz」風のバージョンに変換し、述語を特定の順序でストリームに適用して正しい答えを見つけようとしました。そのようです:
IntStream.range(1, 100).forEach(i -> {
//Order matters here!
if(divisibleByThreeAndFiveAndFour.test(i)){
System.out.println("Three and four and five");
} else if(divisibleByThreeAndFour.test(i)){
System.out.println("Three and four");
} else if(divisibleByThreeAndFive.test(i)){
System.out.println("Three and four");
} else if(divisibleByFive.test(i)){
System.out.println("Five");
}
//etc, etc.
});
これはあまりきれいなコードではないと思います。これを達成するためのより良い方法はありますか?
パート2
適切な値がストリームに存在するかどうかを確認するために述語を適用し、返される関連値 (この場合は出力する文字列) を計算する必要がある場合はどうでしょうか。それはどのように見えるでしょうか?
提案された素朴な解決策:
String bestValueFound = "None found";
if(IntStream.range(1, 100).filter(divisibleByThreeAndFiveAndFour).findFirst().isPresent()){
bestValueFound = "Three and four and five";
} else if(IntStream.range(1, 100).filter(divisibleByThreeAndFour).findFirst().isPresent()){
bestValueFound = "Three and four";
}else if(IntStream.range(1, 100).filter(divisibleByThreeAndFive).findFirst().isPresent()){
bestValueFound = "Three and five";
} else if(IntStream.range(1, 100).filter(divisibleByThreeAndFive).findFirst().isPresent()){
bestValueFound = "Five";
}
System.out.println(bestValueFound);
これは、審美的にも、追加された反復のために、さらに悪いように見えます。
パート3
これは、 JavaSlang Matchを使用して、よりきれいで効率的な方法で解決できるでしょうか?
//Note: Predicates needed to be changed from IntPredicate to Predicate<Integer> for correct compilation.
Function<Integer, String> findString = i -> API.Match(i).of(
Case(divisibleByThreeAndFiveAndFour, "Three and four and five"),
Case(divisibleByThreeAndFour, "Three and four"),
Case(divisibleByThreeAndFive, "Three and five"),
Case(divisibleByFive, "Fice"),
Case($(), "None found"));
String bestValueFound = IntStream.range(1, 100).boxed().map(findString).findFirst().orElseThrow(() -> new RuntimeException("Something went wrong?"));
System.out.println(bestValueFound);
ここでの明らかな問題は、".findFirst()" です。この場合、これは Integer 1 になり、式全体が "None found" と評価されてから終了します。
私が望むのは、基本的に、一致の最初の述語に一致するものをすべて取得し、その値が存在する場合はその値を使用し、最初の一致が見つからない場合は 2 番目のケースに一致するものだけを提供することです。ストリーム内の値がどの述語にも一致しない場合、デフォルト(「見つかりません」)のみを提供します。
これを行うためのより良い方法が必要ですよね?それとも、より伝統的で命令的なスタイルに任せた方がよい何かをしようとして時間を無駄にしているだけですか?
私の質問を読んでくれてありがとう!