,感谢您检查我的问题!
我使用流以特定顺序应用多个谓词的流来缠绕我的头有点麻烦。
为例如,请考虑以下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匹配以更漂亮,更有效的方式解决这?
//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()",在这种情况下,它将是整数1,使整个表达式评估为"无发现",然后终止。
我想要的是基本上抓住与我的比赛中第一个谓词匹配的任何东西,并使用该值,如果存在该值,则只会给我第二种情况,如果找到第一个情况的匹配项,并且因此,仅给我默认值("无发现"),如果流中没有值匹配任何谓词。
必须有一种更好的方法来做到这一点,对吗?还是我只是在浪费时间去做一些更好的传统风格的事情?
感谢您阅读我的问题!
您可以创建一个类来封装谓词及其名称:
class NamedPredicate {
final String name;
final IntPredicate predicate;
NamedPredicate(String name, IntPredicate predicate) {
this.name = name;
this.predicate = predicate;
}
NamedPredicate and(NamedPredicate other) {
return new NamedPredicate(this.name + " and " + other.name,
this.predicate.and(other.predicate));
}
}
and()
方法允许我们将它们组成类似于您最初的方式类似:
NamedPredicate divisibleByThree = new NamedPredicate("three", i -> i % 3 == 0);
NamedPredicate divisibleByFour = new NamedPredicate("four", i -> i % 4 == 0);
NamedPredicate divisibleByFive = new NamedPredicate("five", i -> i % 5 == 0);
NamedPredicate divisibleByThreeAndFour = divisibleByThree.and(divisibleByFour);
NamedPredicate divisibleByThreeAndFive = divisibleByThree.and(divisibleByFive);
NamedPredicate divisibleByThreeAndFiveAndFour = divisibleByThreeAndFour.and(divisibleByFive);
现在,我们可以以降序浏览它们并打印第一个匹配谓词的名称,每个 i
:
IntStream.range(1, 100)
.mapToObj(i -> Stream.of(
divisibleByThreeAndFiveAndFour,
divisibleByThreeAndFour,
divisibleByThreeAndFive,
divisibleByFive,
divisibleByFour,
divisibleByThree)
.filter(p -> p.predicate.test(i))
.findFirst()
.map(p -> p.name)
.orElse("none"))
.forEach(System.out::println);