Python:如何在不跳过未来迭代的情况下迭代时从列表中删除元素

Python: How to remove elements from list while iterating through it without skipping future iterations

在 python 中,我注意到如果我使用 for x in y 遍历列表,并且在循环中删除 y 的一个元素,最后一个元素将是“已跳过”- 我假设这是因为 len(y) 已更改。

我正在尝试抓取具有特定扩展名的所有文件,但满足某些条件的文件除外。

原代码如下:

def test_print_numTXTs(fileList):
    counter = 0
    for file in fileList:
        if file.name[-4:] == ".txt":
            counter +=1
            if file.name == "a.txt":
                fileList.remove(file)   #problem caused here
    print(counter)
    print(len(fileList))

counter 的输出比 .txt 文件总数少一个。通过调试器,我可以看到它正在跳过循环的最后一次迭代(我假设是因为 len(fileList) 现在是 -=1 w.r.t。它的初始 len().

以下代码“有效”,但感觉像是一个 hack - 我将我想从列表中删除的文件添加到第二个列表,然后在事后对其进行迭代。我已经注释掉了我原来的那一行,这导致了迭代的“跳过”。

def print_numTXTs(fileList):
    filesToRemoveFromList = []
    counter = 0
    for file in fileList:
        if file.name[-4:] == ".txt":
            counter +=1
            if file.name == "a.txt":
                #fileList.remove(file) #problem caused here
                filesToRemoveFromList.append(file)
    print(counter)
    for file in filesToRemoveFromList:
        fileList.remove(file)
    print(len(fileList))

此代码输出所有 .txt 文件的计数,列表的长度比它少一个(因为元素 a.txt 已被删除)- 这是所需的行为。

这个问题有更优雅的解决方案吗?

你是对的。你需要一个额外的列表。但是有一个更简单的解决方案。

def print_numTXTs(fileList):

    counter = 0
    for file in list(fileList):
        if file.name[-4:] == ".txt":
            counter +=1
            if file.name == "a.txt":
                fileList.remove(file)
   

秘密是“list(fileList)”。您创建了一个附加列表并对其进行迭代。

列表压缩同样强大。在您的示例中,它应该像这样工作。我现在还没有试过。。。只能赶快写到这里。

fileList = [ file for file in fileList if file.name != "a.txt" ]

我提议忽略最后一个循环:

def test_print_numTXTs(fileList):
    counter = 0
    res = []
    for file in fileList:
        if file.name[-4:] == ".txt":
            counter +=1
            if file.name != "a.txt":
                res.append(file)   #problem caused here
    print(res)

这个解决方案有效。我会考虑他们是否是一种更 pythonic 的方式。

无需手动过滤以 .txt 结尾的文件,您可以 glob 过滤匹配此模式的文件

假设文件夹 foo 包含以下文件:

a.txt  
b.txt  
c.txt 

并且您想计算 *.txt 个文件的数量,a.txt

除外
>>> from pathlib import Path
>>> file_list = Path('foo').glob('*.txt')
>>> sum(1 for f in file_list if f.name.endswith('.txt') and f.name != 'a.txt')
2