0

因此,我试图删除从具有几个标题之一的 excel 表中获取的 2D 数组的所有元素。values 是包含我的数据的二维数组。我的一个主要问题是,并非所有行在最后一列中都有任何需要删除的内容,并导致大量索引越界错误。请注意,二维数组的第一个维度是行。

badColumns = ['Queue', 'Subject', 'Risk', etc...] #Some other ones are here

for col in range(len(values[0])):
    for badText in badColumns:
        if badText in values[0][col]:
            for row in range(len(values)):
                try:
                    del values[row][col]
                except IndexError:
                    continue

在 del 语句周围抛出 print 语句表明 del 语句没有变化。知道是什么原因造成的吗?提前感谢您的帮助。

4

2 回答 2

1

看起来您正在修改列表,因为您正在处理它,这会导致问题。根据您分享的内容,这并不能解释您的所有问题,但应该有所帮助。

运行此代码作为您遇到问题的示例;如果这不能说明问题,我很乐意提供更多帮助:

#Bad Code:

a = range(6)
print a
for i in range(len(a)):
    try:
        del a[i]
    except IndexError:
        print 'Bad index', i
print a

输出:

[0, 1, 2, 3, 4, 5]
Bad index 3
Bad index 4
Bad index 5
[1, 3, 5]

这段代码更好:(也许吧?不是很pythonic,但它可以工作......)

a = range(6)
print a
for i in range(len(a))[::-1]: #the only difference is this reversal
    try:
        del a[i]
    except IndexError:
        print 'Bad index', i
print a

输出:

[0, 1, 2, 3, 4, 5]
[]

以下是错误代码中发生的情况:

首先,a = [0,1,2,3,4,5]

那么,我 = 0

现在 a[i] 被删除了,所以 a = [1,2,3,4,5]

那么,i=1

现在 a[i] 被删除,所以索引 1 处的元素被删除,而不是索引 0

因此,现在 a = [1,3,4,5] 并且您已经跳过删除元素“1”

于 2013-06-03T21:29:36.863 回答
1

您的代码有两个问题。

首先,您不能在遍历序列时对其进行修改。*

其次,如果您在序列中间插入或删除,则会更改以下所有索引。

您可以通过两种方式解决第一个问题:在迭代副本时修改序列,或者在迭代原始副本时构建新副本。

如果您使用前一种(变异)解决方案,通常可以通过向后迭代副本来解决第二个问题。如果您要删除或插入的索引与您正在迭代的索引相同,则可以保证这是安全的,因为它只会触及您已经迭代过的后续索引。

如果您采用后一种解决方案,它会自动解决第二个问题。


附带说明一下,在 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]

*这并不完全正确——您可以替换单个值,并用等长切片替换切片。但是您不能插入或删除元素,或者用不同大小的切片替换切片,并且您正在尝试删除。

于 2013-06-03T22:09:01.073 回答