为什么我的Python循环会跳过一个对象? [duplicate]

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:

由于循环使用了s1s2的副本,因此循环体中对这些列表的更改不会影响p1p2所取的值。

Related Posts

无法理解sklearn的PolynomialFeatures

需要帮助理解sklearn的PolynomialFea…

使用KD树在sklearn中查找多个目标变量的近邻,并使用多个搜索标准

假设这是我正在实现的一个简单的KD树算法 def Te…

Python 3.6: 处理内存错误

我为“机器学习”任务编写了一个软件。 为了完成这个任务…

PyTorch: 图像尺寸问题

我正在处理一个图像分类数据集。我的数据集中有31个类别…

感知器算法 – 代码错误 – Python 3 [duplicate]

这个问题已经有了答案: 我遇到了缩进错误(或制表符错误…

如何处理文本生成中的标记

在我的文本生成数据集中,我已经将所有不常见的词转换成了…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注