正如您所指出的,当您反转示例时,它会变成一个更大的列表:
!((a & b) | (c & d))
!(a & b) & !(c & d) // De Morgan's laws
(!a | !b) & (!c | !d) // De Morgan's laws
(!a & !c) | (!a & !d) | (!b & !c) | (!b & !d) // Normalization
当您再次反转时,列表会变得更大:
!((!a & !c) | (!a & !d) | (!b & !c) | (!b & !d))
!(!a & !c) & !(!a & !d) & !(!b & !c) & !(!b & !d) // De Morgan's laws
(!!a | !!c) & (!!a | !!d) & (!!b | !!c) & (!!b | !!d) // De Morgan's laws
(a | c) & (a | d) & (b | c) & (b | d) // Double negation
(a & a & b & b) | (a & a & b & d) | (a & a & c & b) | (a & a & c & d) | (a & d & b & b) | (a & d & b & d) | (a & d & c & b) | (a & d & c & d) | (c & a & b & b) | (c & a & b & d) | (c & a & c & b) | (c & a & c & d) | (c & d & b & b) | (c & d & b & d) | (c & d & c & b) | (c & d & c & d) // Normalization
哇,最后一行肯定很长!您会注意到一些连词从句有重复,即a & a & b & b
. 因此,第一步是删除重复的谓词:
(a & b) | (a & b & d) | (a & c & b) | (a & c & d) | (a & d & b) | (a & d & b) | (a & d & c & b) | (a & d & c) | (c & a & b) | (c & a & b & d) | (c & a & b) | (c & a & d) | (c & d & b) | (c & d & b) | (c & d & b) | (c & d)
现在我们可以对每个连词中的谓词进行排序,并删除重复的连词:
(a & b) | (a & b & c) | (a & b & c & d) | (a & b & d) | (a & c & d) | (b & c & d) | (c & d)
好的,这清除了很多!但是,我们仍然在这个表达式中得到了比我们开始时更多的东西。但是,如果您仔细观察,其中一些连词是多余的-例如a & b & c => a & b
. 所以,如果一个连词是另一个连词的超集,我们可以删除它:
(a & b) | (c & d)
原始条款!由于您的问题中没有包含任何代码,因此我的答案中不会包含任何代码 - 实施上述步骤取决于您。但是,我建议您简化模型:
public class Predicate
{
public string Field { get; set; }
public Operator Operator { get; set; }
public string Value { get; set; }
}
public enum NormalForm
{
Conjunctive,
Disjunctive
}
public class Filter
{
public NormalForm NormalForm { get; set; }
public List<List<Predicate>> Predicates { get; set; }
}
这是一种更灵活的表示,并且会使反演更容易,因为在您应用德摩根定律之后,您最终会得到合取范式并且必须转换回来。