如何异或谓词?
How to xor predicates?
我需要一个方法,我需要 xor 谓词,我将接收这些谓词作为方法参数。对于两个谓词,我有一个有点工作但麻烦的解决方案。举一个简单、最小和可重现的例子:
Predicate<String> pred1 = s -> s.contains("foo");
Predicate<String> pred2 = s -> s.contains("bar");
String toTest = "foobar";
对于给定的谓词和测试字符串,逻辑 OR 将 return true
:
boolean oneOnly = pred1.or(pred2).test(toTest);
但对于我的用例,它应该 return false 因为两个子字符串都包含在内。当且仅当满足一个条件时,它才应该 return 为真。
对于两个 predicates 我有这个
static boolean xor(Predicate<String> pred1, Predicate<String> pred2, String toTest){
return pred1.and(pred2.negate()).or(pred2.and(pred1.negate())).test(toTest);
}
是否有一种简单但方便的异或谓词方法?
更新:
下面是一些您想要 return 谓词而不是布尔值的示例,但是@rzwitserloot 的 做得很好而且更简洁。
唱反调:它不那么漂亮,但你已经拥有它的一个优势是你稍微更符合谓词习语。稍作调整即可获得:
Return 谓词
static <T> Predicate<T> xor(Predicate<T> pred1, Predicate<T> pred2){
return pred1.and(pred2.negate())
.or(pred2.and(pred1.negate()));
}
// Which means you can do this, which is probably more conducive to combining your
// new xor function with other predicates:
xor((Integer a) -> a > 1, (Integer b) -> b < 10).test(0));
// For example, because you return a Predicate:
xor((Integer a) -> a > 1, (Integer b) -> b < 10).negate().test(0));
Return 布尔值
static <T> boolean xor(Predicate<T> pred1, Predicate<T> pred2, T toTest) {
return pred1.test(toTest) ^ pred2.test(toTest);
}
// In contrast, if your xor function returns a boolean, you get this, which is
// similar, but is less conducive to using all the Predicate methods:
xor((Integer a) -> a > 1, (Integer b) -> b < 10, 14);
// To be honest, this seems more readable to me than the negate() function in the
// example above, but perhaps there are scenarios where the above is preferred...
!xor((Integer a) -> a > 1, (Integer b) -> b < 10, 14)
没什么大不了的,但你的问题让我很好奇...
跟进@xdhmoore 的回答,这太过分了,可以做得更简单:
static <T> Predicate<T> xor(Predicate<T> pred1, Predicate<T> pred2) {
return t -> pred1.test(t) ^ pred2.test(t);
}
您可以使用 stream.reduce 将异或谓词简化为单个谓词,然后 return 结果。
像这样:
import java.util.function.Predicate;
import java.util.Arrays;
public class MultiXor{
public static void main(String[] args){
System.out.println(xor("monkey", p -> p.equals("monkey"), p -> p.equals("dork"), p -> p.equalsIgnoreCase("Monkey")) );
System.out.println(true ^ false ^ true);
System.out.println(xor("monkey", p -> p.equals("monkey"), p -> p.equals("dork")) );
System.out.println(true ^ false);
}
public static <T> boolean xor(final T param, Predicate<T>... predicates){
return Arrays.stream(predicates).reduce( p -> false, (previous, p) -> r -> previous.test(param) ^ (p.test(param))).test(param);
}
}
我需要一个方法,我需要 xor 谓词,我将接收这些谓词作为方法参数。对于两个谓词,我有一个有点工作但麻烦的解决方案。举一个简单、最小和可重现的例子:
Predicate<String> pred1 = s -> s.contains("foo");
Predicate<String> pred2 = s -> s.contains("bar");
String toTest = "foobar";
对于给定的谓词和测试字符串,逻辑 OR 将 return true
:
boolean oneOnly = pred1.or(pred2).test(toTest);
但对于我的用例,它应该 return false 因为两个子字符串都包含在内。当且仅当满足一个条件时,它才应该 return 为真。
对于两个 predicates 我有这个
static boolean xor(Predicate<String> pred1, Predicate<String> pred2, String toTest){
return pred1.and(pred2.negate()).or(pred2.and(pred1.negate())).test(toTest);
}
是否有一种简单但方便的异或谓词方法?
更新:
下面是一些您想要 return 谓词而不是布尔值的示例,但是@rzwitserloot 的
唱反调:它不那么漂亮,但你已经拥有它的一个优势是你稍微更符合谓词习语。稍作调整即可获得:
Return 谓词
static <T> Predicate<T> xor(Predicate<T> pred1, Predicate<T> pred2){
return pred1.and(pred2.negate())
.or(pred2.and(pred1.negate()));
}
// Which means you can do this, which is probably more conducive to combining your
// new xor function with other predicates:
xor((Integer a) -> a > 1, (Integer b) -> b < 10).test(0));
// For example, because you return a Predicate:
xor((Integer a) -> a > 1, (Integer b) -> b < 10).negate().test(0));
Return 布尔值
static <T> boolean xor(Predicate<T> pred1, Predicate<T> pred2, T toTest) {
return pred1.test(toTest) ^ pred2.test(toTest);
}
// In contrast, if your xor function returns a boolean, you get this, which is
// similar, but is less conducive to using all the Predicate methods:
xor((Integer a) -> a > 1, (Integer b) -> b < 10, 14);
// To be honest, this seems more readable to me than the negate() function in the
// example above, but perhaps there are scenarios where the above is preferred...
!xor((Integer a) -> a > 1, (Integer b) -> b < 10, 14)
没什么大不了的,但你的问题让我很好奇...
跟进@xdhmoore 的回答,这太过分了,可以做得更简单:
static <T> Predicate<T> xor(Predicate<T> pred1, Predicate<T> pred2) {
return t -> pred1.test(t) ^ pred2.test(t);
}
您可以使用 stream.reduce 将异或谓词简化为单个谓词,然后 return 结果。
像这样:
import java.util.function.Predicate;
import java.util.Arrays;
public class MultiXor{
public static void main(String[] args){
System.out.println(xor("monkey", p -> p.equals("monkey"), p -> p.equals("dork"), p -> p.equalsIgnoreCase("Monkey")) );
System.out.println(true ^ false ^ true);
System.out.println(xor("monkey", p -> p.equals("monkey"), p -> p.equals("dork")) );
System.out.println(true ^ false);
}
public static <T> boolean xor(final T param, Predicate<T>... predicates){
return Arrays.stream(predicates).reduce( p -> false, (previous, p) -> r -> previous.test(param) ^ (p.test(param))).test(param);
}
}