如何异或谓词?

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);
    }

}