在python中从2D列表中获取特定元素时遇到问题
因此,我试图删除一个二维数组中的所有元素,该数组是从一个excel工作表中获取的,带有几个标题中的一个。值是包含我的数据的二维数组。我的主要问题之一是,并非所有行的最后一列中都有需要删除的内容,这会导致大量索引越界错误。注意,二维数组的第一个维度是行在python中从2D列表中获取特定元素时遇到问题,python,excel,multidimensional-array,indexoutofboundsexception,Python,Excel,Multidimensional Array,Indexoutofboundsexception,因此,我试图删除一个二维数组中的所有元素,该数组是从一个excel工作表中获取的,带有几个标题中的一个。值是包含我的数据的二维数组。我的主要问题之一是,并非所有行的最后一列中都有需要删除的内容,这会导致大量索引越界错误。注意,二维数组的第一个维度是行 badColumns = ['Queue', 'Subject', 'Risk', etc...] #Some other ones are here for col in range(len(values[0])): for badTe
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语句的任何更改。知道这是什么原因吗?提前感谢您的帮助。看起来您正在修改列表,这会导致出现问题。根据你分享的内容,这并不能解释你所有的问题,但应该会有所帮助 运行此代码作为您遇到问题的示例;如果这不能清楚地说明问题,我很乐意提供更多帮助:
#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]
[0, 1, 2, 3, 4, 5]
[]
这段代码更好:(嗯,也许吧?不太像Python,但它能工作…)
输出:
[0, 1, 2, 3, 4, 5]
Bad index 3
Bad index 4
Bad index 5
[1, 3, 5]
[0, 1, 2, 3, 4, 5]
[]
下面是坏代码中发生的情况:
首先,a=[0,1,2,3,4,5]
那么,i=0
现在a[i]被删除,因此a=[1,2,3,4,5]
那么,i=1
现在a[i]被删除,因此索引1处的元素被删除,而不是索引0
因此,现在a=[1,3,4,5],您已经跳过了删除元素“1”您的代码有两个问题 首先,不能在遍历序列时对其进行修改*
第二,如果在序列中间插入或删除,则会改变所有以下索引。
可以用两种方法解决第一个问题:在迭代副本时修改序列,或者在迭代原始副本时构建新副本 如果使用前一种(变异)解决方案,通常可以通过向后迭代副本来解决第二个问题。如果您正在删除或插入的索引与您正在迭代的索引相同,那么这保证是安全的,因为它只会触及您已经迭代过的后面的索引 如果使用后一种解决方案,它会自动解决第二个问题作为旁注,在Python中迭代序列的最简单方法是直接进行迭代,而不是构建
范围(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]
如果您需要通过适当地改变
值
来执行此操作(例如,因为某些其他代码引用了值
,并且必须看到它发生了变化),这里有一个等价的:
# 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
(或orderedict
,如果您需要保留列顺序)而不是列表,则可以执行以下操作:
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]
*这并不完全正确,您可以替换单个值,并用等长切片替换切片。但是您不能插入或删除元素,也不能用不同大小的切片替换切片,并且您正在尝试删除。为什么不确定要删除哪些列呢?这似乎是IndexOutofBounds的来源,但您仍在尝试在遍历它时找到修改的方法。我怎么能不这样做呢?我现在没有想出任何好的解决办法。。。尝试在原始代码中使用[::-1]
,看看它是否正确helps@avorum删除或插入序列中间会改变所有以下索引,这意味着您将跳过或重复其中一个元素。解决方法是向后迭代序列,如答案所示。同时,您不能在遍历序列时实际修改它;您必须在遍历序列副本时修改原始副本,或者在遍历原始副本时构建副本(后者通常更具Pythonic)。我无法决定是建议您创建副本(更具Pythonic)还是仅删除元素(更高效)。。。我可以告诉你,为了进行调试,你应该用某种打印语句替换continue
。你知道关于理解的好教程吗?我经常看到它们,语法对我来说毫无意义。@avorum:我不知道有什么比官方教程中的内容更好的了,所以如果没有帮助的话……我很快就写了一些东西;如果有帮助,请告诉我。