为什么我的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

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

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