为什么我的代码不适用于单个列表,而适用于嵌套列表



当有多个列表传递到函数中时,第一个打印系统就会工作。然而,当只传入一个列表时,我会得到错误"AttributeError:'int'对象没有属性'pop'"

此代码试图从列表中删除一个项目,以查看弹出的项目是否仍存在于其余列表中。

def check_row(p):
    for e in p:
        while e:
            x = e.pop()
            if x in e:
                return False
    return True

print check_row([[8,2,3,4,5],
              [2,3,1,5,6],
              [4,0,2,3,1]])
print check_row([1,2,3,4,5])

非常感谢。

您弹出的是元素中的项目,而不是外部列表。如果您的元素不是列表,那么不要试图将它们视为列表。

但是,不能在循环外部列表的同时从外部列表中删除项目,并且期望循环不会跳过项目。

如果您想查看一个项目是否在列表中出现不止一次,请比较列表的set()的长度:

def check_row(row):
    return len(row) == len(set(row))

这只适用于可散列值,而嵌套列表不是,但至少不会像您的代码那样更改列表

您仍然可以使用列表扫描,但至少可以使用list.index()将搜索限制在当前位置之外的起始索引:

def check_row(row):
    for i, elem in enumerate(row):
        try:
            row.index(elem, i + 1)
            return False  # dupe found
        except ValueError:
            pass  # no dupe found
    return True

但是,这假设您只想测试外部列表中的重复项。在同一代码中支持嵌套结构和平面结构,而不详细说明每种情况下会发生什么,这要复杂得多。

在单个(非嵌套)列表的情况下,对不是列表的元素(e)调用.pop(),因此可能没有.pop方法。

这是因为e是列表中的一个元素。在嵌套式中,e是一个列表,而在第二个嵌套式中e是一个整数。因此,e.pop对于第二个无效。

你必须使它始终嵌套:

>>> print(check_row([[1, 2, 3, 4, 5]]))
True

这样,传递给check_row的值总是一个嵌套列表,即使它只有一个元素。

但就检查元素是否仍在其他列表中而言,我会首先将列表压平,然后检查列表中是否有重复的元素。

import collections
def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, str):
            for sub in flatten(el):
                yield sub
        else:
            yield el
def check_row(p):
    flat = list(flatten(p))
    return len(flat) == len(set(flat))

这样,check_row将始终生成您想要的结果,忽略它是列表或嵌套列表的事实:)

希望这能有所帮助!

您的命名混淆了自己。您调用的check_row函数实际上会检查行的列表,而不管名称如何,因此将其传递给一行会失败。事实上,你使用了毫无意义的一个字母的名字也无济于事。让我们重写得更清楚:

如果你想要一个检查单行的函数,

def check_rows(rows):
    for row in rows:
        while row:
            element = row.pop()
            if element in row:
                return False
    return True

现在应该更清楚它失败的原因了:您将一个row作为rows传递给它,所以for row in rows得到的是元素而不是行,从那以后一切都会走下坡路。


您可能想要的是一个在单行上工作的check_row函数,然后是在每行上调用check_rowcheck_rows

def check_row(row):
    while row:
        element = row.pop()
        if element in row:
            return False
    return True
def check_rows(rows):
    for row in rows:
        if not check_row(row):
            return False
    return True

但实际上,我不知道你为什么想要这个函数。它破坏性地修改行,删除第一个重复之前的每个元素。你为什么要那样?例如,Martijn Pieters的解决方案更简单、更高效,而且是无损的:

def check_row(row):
    return len(set(row)) == len(row)

在我们讨论的时候,让我们使用all函数,而不是check_rows:的显式循环

def check_rows(rows):
    return all(check_row(row) for row in rows)

最新更新