为什么这个循环永远不会超过列表中的第一项?

时间:2015-03-18 02:19:15

标签: python list

我有一个函数,它应该将矩阵奇数行中的每个元素递增5,偶数行中的每个元素递增10.我编写了下面的代码:

def incrementRows(matrix):
    for i in matrix:
        print(matrix.index(i))

        if matrix.index(i) % 2 == 0:
            matrix[matrix.index(i)] = [x + 5 for x in matrix[matrix.index(i)]]
        else:
            matrix[matrix.index(i)] = [x + 10 for x in matrix[matrix.index(i)]]


    return matrix


matrix = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]

print(incrementRows(matrix))

这段代码的问题在于,通过函数中的print(matrix.index(i))语句判断,循环从不传递列表中的第一项。我不明白为什么。以下是输出:

0
0
0
[[16, 17, 18, 19, 20], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]

如果我从函数中取出If / else语句,那么循环将正确迭代列表中的每个项目。

def incrementRows(matrix):
    for i in matrix:
        print(matrix.index(i))

    return matrix


matrix = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]

print(incrementRows(matrix))

结果:

0
1
2
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]

有人能告诉我为什么函数中的If / else语句阻止循环遍历列表中的每个项目吗?

4 个答案:

答案 0 :(得分:2)

根据您提供的数据,您将在每一步更改矩阵,以确保始终在索引0处找到其中的下一项。

要检查,请更改

print(matrix.index(i))

print(i, matrix, matrix.index(i))

你会看到更多信息量的输出:

[1, 2, 3, 4, 5] [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] 0
[6, 7, 8, 9, 10] [[6, 7, 8, 9, 10], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] 0
[11, 12, 13, 14, 15] [[11, 12, 13, 14, 15], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] 0

请参阅?每次,您都要更改第0个索引,使其等于矩阵中的下一个项目。

循环列表的项目,然后对列表中的每个项目进行.index,当然,总会找到第一次出现的每个项目的副本 - 除了浪费在任何情况下进行大量计算(制作一个O(N平方)的循环当然应该是O(N))这会在像你这样的情况下引起真正奇怪的结果。

要恢复理智,请更改部分:

def incrementRows(matrix):
    for i in matrix:
        print(matrix.index(i))

to,例如

def incrementRows(matrix):
    for where in range(len(matrix)):
        print(where)

并在其他任何地方使用where,无论你现在正在重新计算(浪费可笑的循环次数)matrix.index(i)

答案 1 :(得分:1)

问题在于,在第二次迭代中,第一项和第二项比较相等,因此索引只会再次为您提供第一项。

我相信是时候了解enumerate()了。基本上这里i只是索引而不必一遍又一遍地扫描列表中的匹配。

def incrementRows(matrix):
    for i, item in enumerate(matrix):
        print(i)

        if i % 2 == 0:
            matrix[i] = [x + 5 for x in item]
        else:
            matrix[i] = [x + 10 for x in item]


    return matrix


matrix = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]

print(incrementRows(matrix))

代码更容易阅读,现在可以正常使用

答案 2 :(得分:1)

这里使用list-comp会更加直截了当,并将模数基于你在条件表达式中迭代的“行号”,以选择添加5或10,例如:

matrix = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]
result = [
    [n + 5 if rowno % 2 == 0 else n + 10 for n in row] 
    for rowno, row in enumerate(matrix)
]
# [[6, 7, 8, 9, 10], [16, 17, 18, 19, 20], [16, 17, 18, 19, 20]]

答案 3 :(得分:0)

首先,你在迭代它时修改列表的结构。 Don't do that

但我认为你这样做是因为你没有意识到这是做什么的:

for i in matrix:
    print(matrix.index(i))

我不知道你是否意识到这一点,但i将成为迭代中该循环列表中的元素。一个例子:

matrix = [[1,2],[3,4],[5,6]]
for row in matrix:
    print(row)

输出:

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

使用简单的线性搜索,matrix.index(i)将导致列表i中的'值'matrix的索引。

如果你想在索引上使用“c-style”for循环,你可以这样做:

for i in xrange(len(matrix)): # Use just range(len(matrix)) if python 3.X
    print(matrix[i])

然而,python有一个漂亮的方法enumerate,它将为迭代器中的某个位置提供索引和值。

在这种情况下,您的代码将变为以下内容:

def increment_rows(matrix):
    for i,row in enumerate(matrix):
        print(i,row)
        matrix[i] = [v + 5 for v in row] if i % 2 else [v + 10 for v in row]
    print(matrix)
    return matrix

这将产生您想要的输出。当然,您实际上可以将其合并为一个单行列表,并使用enumerate

def increment_rows(matrix):
    return [([v + 5 for v in row] if i % 2 else [v + 10 for v in row]) for i,row in enumerate(matrix)]