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
在 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