您的代码有两个问题。
首先,您不能在遍历序列时对其进行修改。*
其次,如果您在序列中间插入或删除,则会更改以下所有索引。
您可以通过两种方式解决第一个问题:在迭代副本时修改序列,或者在迭代原始副本时构建新副本。
如果您使用前一种(变异)解决方案,通常可以通过向后迭代副本来解决第二个问题。如果您要删除或插入的索引与您正在迭代的索引相同,则可以保证这是安全的,因为它只会触及您已经迭代过的后续索引。
如果您采用后一种解决方案,它会自动解决第二个问题。
附带说明一下,在 Python 中迭代序列的最简单方法是直接进行,而不是构建 arange(len())
然后索引。如果您也需要索引,可以使用enumerate
.
无论如何,您似乎想要做的是删除其标题值包含任何 badColumns 名称的任何列,对吗?让我们将其重写为一个非变异函数,该函数在没有这些列的情况下构建一个新表。
def isBadColumn(text):
for badText in badColumns:
if badText in text:
return True
badIndices = set()
for idx, header in enumerate(values[0]):
if isBadColumn(header):
badIndices(idx)
newValues = []
for row in values:
newRow = []
for idx, col in enumerate(row):
if idx not in badIndices:
newRow.append(col)
newValues.append(newRow)
values = newValues
但是所有这些显式for
循环都可以很容易地转化为理解,所以整个事情都简化为:
badIndices = {idx for idx, header in enumerate(values[0])
if any(badText in header for badText in badColumns)}
values = [[col for idx, col in row if idx not in badIndices] for row in values]
如果您需要通过values
就地变异来做到这一点(例如,因为其他一些代码有引用values
并且必须看到它发生变化),这里有一个等价的:
# all of the code to get badIndices from above
for rowidx, row in reversed(enumerate(values)):
for colidx, col in reversed(enumerate(row)):
if colidx in badIndices:
del values[rowidx][colidx]
同时,您可能首先要考虑不同的数据结构。例如,如果您将每一行存储为dict
(或者OrderedDict
,如果您需要保留列顺序)而不是 a list
,您可以这样做:
badHeaders = {header for header in values[0]
if any(badText in header for badText in badColumns)}
然后构建一个新副本:
values = [{header: value for header, value in row.items()
if header not in badColumns}
for row in values]
或原地变异:
for row in values:
for header in badHeaders:
del row[header]
*这并不完全正确——您可以替换单个值,并用等长切片替换切片。但是您不能插入或删除元素,或者用不同大小的切片替换切片,并且您正在尝试删除。