матрицы python - индекс списка вне диапазона

Эй, я пишу функцию, которая принимает на вход матрицу, такую ​​​​как приведенная ниже, и возвращает ее обратную, где все 1 заменяются на 0, а все 0 заменяются на 1, сохраняя при этом диагональ от верхнего левого до нижнего правого 0.



Пример ввода:

g1 = [[0, 1, 1, 0],
     [1, 0, 0, 1],
     [1, 0, 0, 1],
     [0, 1, 1, 0]]



функция должна вывести следующее:

g1 = [[0, 0, 0, 1],
     [0, 0, 1, 0],
     [0, 1, 0, 0],
     [1, 0, 0, 0]]



Когда я запускаю программу, она выдает ошибку "индекс списка вне допустимого диапазона". Я уверен, что это связано с тем, что созданные мной циклы пытаются получить доступ к несуществующим значениям, но как мне разрешить ввод неизвестного размера строки и столбца? Я знаю, как это сделать только с одним списком, но список списков? Вот функция, не включая тестовую функцию, которая ее вызывает:

def inverse_graph(graph):
    # take in graph
    # change all zeros to ones and ones to zeros

    r, c = 0, 0 # row, column equal zero

    while (graph[r][c] == 0 or graph[r][c] == 1): # while the current row has a value.
        while (graph[r][c] == 0 or graph[r][c] == 1): # while the current column has a value
            if (graph[r][c] == 0):
                graph[r][c] = 1
            elif (graph[r][c] == 1):
                graph[r][c] = 0
            c+=1
        c=0
        r+=1

    c=0
    r=0

    # sets diagonal to zeros

    while (g1[r][c] == 0 or g1[r][c] == 1):
        g1[r][c]=0
        c+=1
        r+=1

    return graph

person kylecblyth    schedule 08.12.2012    source источник
comment
Я думаю, читабельность, правильность и скорость вашего кода значительно улучшится, если вы потратите некоторое время на изучение понимание списка   -  person erikbwork    schedule 09.12.2012
comment
Если вы используете много матриц/двухмерных массивов, NumPy очень полезен.   -  person ninMonkey    schedule 09.12.2012


Ответы (5)


Это не дает прямого ответа на ваш вопрос, но я хочу отметить, что в Python вы часто можете уменьшить, а иногда и устранить необходимость использования индексации с помощью оператора
for <element> in <container>:
. Используя его вместе со встроенной функцией enumerate(), можно получить как индекс, так и соответствующий элемент
for <index>,<element> in enumerate(<container>):

Применение их к вашей проблеме позволит что-то вроде этого:

g1 = [[0, 1, 1, 0],
      [1, 0, 0, 1],
      [1, 0, 0, 1],
      [0, 1, 1, 0]]

def inverse_graph(graph):
    """ invert zeroes and ones in a square graph
        but force diagonal elements to be zero
    """
    for i,row in enumerate(graph):
        for j,cell in enumerate(row):
            row[j] = 0 if cell or i == j else 1
    return graph

print(g1)
print(inverse_graph(g1))

Выход:

[[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]]
[[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]]

Что проще и понятно работает. Еще один момент заключается в том, что, поскольку вы применяете функцию к изменяемому (изменяемому) контейнеру, списку списков, нет необходимости возвращать контейнер, поскольку он изменяется на месте. В этом нет ничего плохого, потому что это может упростить использование функции, но вы, возможно, этого не осознавали.

Вы можете еще немного сократить функцию и полностью отказаться от индексации, используя нечто, называемое list comprehension:

def inverse_graph(graph):
    return [[0 if cell or i == j else 1
                for j,cell in enumerate(row)]
                    for i,row in enumerate(graph)]

Из-за того, как они работают, эта версия не изменяет график на месте, а вместо этого создает и возвращает новый.

person martineau    schedule 08.12.2012
comment
Благодарю вас! Это очень помогает! - person kylecblyth; 09.12.2012
comment
@martineau Я должен упомянуть, что ваш вывод не совсем соответствует задаче. В конечном итоге вы меняете диагональные элементы (которые должны оставаться 0-ми). В остальном хороший ответ. - person IamAlexAlright; 09.12.2012
comment
@IamAlexAlright: Ой, моя ошибка, которую я исправил. Спасибо, что указали на упущение. Надеюсь, вы все еще считаете это хорошим ответом. - person martineau; 09.12.2012

while (graph[r][c] == 0 or graph[r][c] == 1): # while the current row has a value.

Вы должны сначала убедиться, что оба индекса существуют, прежде чем сравнивать его возможное значение с 0 или 1. Это вызывает ваши исключения. Чтобы инвертировать вашу матрицу, вы хотели бы сделать что-то вроде

for row in graph:
    for idx, v in enumerate (row):
        row [idx] = 0 if v else 1
person Hyperboreus    schedule 08.12.2012

Ошибка в вашем «пока текущая строка имеет значение». Это будет всегда верно, пока вы будете перебирать элементы в строке, и когда вы пройдете мимо них, вы получите исключение.

Вместо этого используйте:

for r in range(len(graph):
    for c in range(len(graph[0]):
        # do something with graph[r][c]
person kaspersky    schedule 08.12.2012

Это довольно просто. В основном вам нужно найти количество элементов в массиве

 mylist = [1,2,3,4,5]
 len(mylist) # returns 5
 #this gives the number of elements.
 rows=len(g1) # get the number of rows
 columns=len(g1[0]) #get the number of columns
 #Now iterate over the number of rows and columns
 for r in range(0, rows):
    for c in range (0,columns):
       if (r==c):
              g1[r][c]=0
       else:
           g1[r][c]=1-g1[r][c]

надеюсь, это поможет

person Manas Paldhe    schedule 08.12.2012

Не ответ на ваш вопрос, но вот «простой» способ сделать это

return [[0 if i2==i else 1 if item == 0 else 0 for i2,item in enumerate(row)] for i,row in graph]

person IamAlexAlright    schedule 08.12.2012