def resolveSentences(s1, s2):
"""给定两个句子s1和s2,返回解析后的句子"""
clauses = []
for p1 in s1:
for p2 in s2:
if p1.name == p2.name and p1.sign != p2.sign:
s1 = remove(p1, s1)
s2 = remove(p2, s2)
s = None
if s1 and s2:
s = list(set(s1).union(s2))
elif s1 and not s2:
s = list(set(s1))
elif s2 and not s1:
s = list(set(s2))
if s:
for pred in s:
clauses.append(pred)
if len(clauses) > 0:
return clauses
else:
return None
我调用函数的方式如下:
if __name__ == "__main__":
p1 = convertToPredicate("A(x)")
p2 = convertToPredicate("B(x)")
p3 = convertToPredicate("~A(x)")
p4 = convertToPredicate("~B(x)")
p5 = convertToPredicate("C(x)")
s1 = [p1, p2, p5]
# A(x)| B(x) | C(x)
s2 = [p3, p4]
# ~A(x)| ~B(x)
trial = resolveSentences(s1, s2)
for t in trial:
print(t.sign, t.name, t.arguments, sep="\t")
我的预期答案是:C(x)
我的当前答案是:B(x)| ~B(x)| C(x)
问题:为什么没有移除B(x)?
我的观察:
在resolveSentences()函数中,第一个for循环跳过了第二个谓词。我无法弄清楚为什么会这样。任何帮助都将不胜感激。
remove函数如下:
def equals(p1, p2):
"""如果谓词p1等于p2,则返回True"""
if p1.name == p2.name:
if p1.sign == p2.sign:
return True
return False
def remove(predicate_to_remove, sentence):
"""从句子中移除所有谓词的实例,并返回一个谓词列表"""
for predicate in sentence:
if equals(predicate_to_remove, predicate):
sentence.remove(predicate)
return sentence
Predicate是一个类,具有以下属性:name, sign, constants, variables, arguments
Predicate类的定义如下:
class Predicate:
"""确定谓词的内容。
sign: 如果为负,则为1,否则为正"""
name = None
sign = None
constants = None
variables = None
arguments = None
def __init__(self):
self.arguments = []
self.name = ""
self.sign = 0
self.constants = []
self.variables = []
convertToPredicate函数如下:
def convertToPredicate(query):
"""将原始输入转换为Predicate类的对象
(str) -> (Predicate)"""
std_predicate = Predicate()
# 确定谓词的符号
std_predicate.sign = 1 if query[0] == "~" else 0
query = query.replace("~", "")
# 确定谓词的名称
std_predicate.name = query[:query.find("(")]
# 确定谓词的参数/变量/常量
std_predicate.arguments = query[query.find("(")+1:query.find(")")].replace(" ", "").split(",")
for arg in std_predicate.arguments:
if arg[0].isupper():
std_predicate.constants.append(arg)
elif arg[0].islower():
std_predicate.variables.append(arg)
return std_predicate
回答:
文档说明这是预期的行为:
注意:当序列在循环中被修改时(这只能发生在可变序列,即列表上),会有一个内部计数器用于跟踪下一个要使用的项目,并且每次迭代时这个计数器都会增加。当这个计数器达到序列的长度时,循环终止。这意味着如果套件从序列中删除了当前(或之前的)项目,下一个项目将被跳过(因为它获得了当前项目的索引,而该项目已经被处理过)。同样,如果套件在当前项目之前插入了一个项目,当前项目将在下一次循环中再次被处理。
避免这种情况的一种方法是使用列表的副本来驱动for
循环。
而不是这样:
for p1 in s1:
for p2 in s2:
使用这样:
base_s1 = s1[:]
base_s2 = s2[:]
for p1 in base_s1:
for p2 in base_s2:
由于循环使用了s1
和s2
的副本,因此循环体中对这些列表的更改不会影响p1
和p2
所取的值。