在列表中找到矛盾

时间:2017-03-20 09:19:04

标签: python list logic

我有很多名单,我想找到是否与其他人相矛盾。 列表不会与他们自己发生冲突,所有关系仅为'>''<'

list1 = ["a<4", "b<3", "c<3", "d<6"]
list2 = ["b<6", "a<1", "c<5", "d<2"]
list3 = ["a>7", "c<2", "b>1", "d<8"]

在上述情况下,list3list1相矛盾,因为"a"不能同时大于7且小于4。

另一个例子

list4 = ["a<4", "b<3", "c>2", "d<8"]
list5 = ["b<6", "a<6", "c<5", "d>9"]
list6 = ["a>2", "b>1", "d<8", "c<9"]

在这种情况下,list5list4相矛盾,因为"d"不能同时大于9且小于8。

2 个答案:

答案 0 :(得分:2)

您可以简单地为每个包含上限和下限的变量维护一个列表。如果变量没有上限或下限,则可以使用None

每次评估约束时,都会相应地更新列表,当下限大于上限时,我们知道存在冲突。

现在我们只需要几个部分:

  • 一个解析步骤,用于派生约束;
  • 维护并检查边界的变量管理器

变量管理器可以如下工作:

def update_variables(var_dict,variable,constraint,value):
    la = var_dict.get(variable)
    if la is None:
        la = [None,None]
        var_dict[variable] = la
    if constraint == '>' and (la[0] is None or value > la[0]):
        la[0] = value
    elif constraint == '<' and (la[1] is None or value < la[1]):
        la[1] = value
    return la[0] is None or la[1] is None or la[0] < la[1]

首先,我们检查变量是否已经是字典的一部分。如果不是,我们添加[None,None]。接下来,我们通过更新与约束对应的索引来更新边界('>'为0,'<'为1)。我们最后检查是否仍然可以绑定。就是这种情况,我们返回True。否则我们返回False。从这种绑定错误的那一刻起,我们就知道这两个列表是冲突的。

现在我们仍然需要处理列表并相应地更新管理器。因此我们开发了一个正则表达式:

(\w+)\s*(<|>)\s*(-?\d+)

因此,我们假设每个字符串都具有格式\w+(变量的名称),后跟'<''>',最后是值-?\d+。每次我们从列表中获取此类字符串,解析它,更新管理器并检查配置是否仍然有效。所以这看起来像:

import re

def conflict(lista,listb):
    manager = {}
    rgx = re.compile(r'(\w+)\s*(<|>)\s*(-?\d+)')
    for listi in (lista,listb):
        for constraint in listi:
            mat = rgx.match(constraint)
            if mat:
                var,con,val = mat.groups()
                val = int(val)
                if not update_variables(manager,var,con,val):
                    return True # the lists are conflicting
            else:
                raise Exception('Could not parse constraint "%s"'%constraint)
    return False # the lists do not conflict

这会产生:

>>> conflict(list3,list1)
True
>>> conflict(list1,list1)
False
>>> conflict(list1,list2)
False
>>> conflict(list1,list3)
True
>>> conflict(list2,list3)
True

答案 1 :(得分:2)

你可以试试SymPy。

from sympy.solvers import solve
from sympy import symbols
from sympy.parsing.sympy_parser import parse_expr

a, b, c, d = symbols('a b c d')
list1 = ["a<4", "b<3", "c<3", "d<6"]
list2 = ["b<6", "a<1", "c<5", "d<2"]
list3 = ["a>7", "c<2", "b>1", "d<8"]

l1 = [parse_expr(eq) for eq in list1]
l2 = [parse_expr(eq) for eq in list2]
l3 = [parse_expr(eq) for eq in list3]

print(solve(l1 + l2))
print(solve(l1 + l3))
print(solve(l2 + l3))

列表中的字符串将使用parse_expr解析为不等式。然后,您必须将列表与+连接起来,并尝试一次解决8个不等式。如果你得到False,那么这是不可能的,因此你有一个矛盾。否则,您可以获得a, b, c, d的正确值的表达式,以实现不等式。所以你可以这样写:

def contradiction(l_i, l_j):
    s = solve(l_i + l_j)
    if s==False: return True
    else: return False

当然,如果你有很多字符串列表,那么你必须找到一种方法来组合所有列表,就像我在这里手动一样,因为只有三种组合l1 + l2l1 + l3和{{ 1}}。此外,您应该注意,对于大型列表,性能可能会变差。