Почему удаляется объект из массива Python
Решаю вот эту кату на codewars. Задание вкратце: посчитать определитель квадратной матрицы произвольного размера. Собственно, мое решение:
def determinant(matrix):
print('Matrix: ',matrix)
def minor(i,m):
#здесь специально копирую переданную матрицу, чтобы с ней ничего не случилось
major=m.copy()
print('Major: ',major)
major.pop(0)
for row in major:
row.pop(i)
print('Minor: ',major)
return major
if len(matrix)==1:
print('Det: ',matrix[0][0])
return matrix[0][0]
sum=0
for j in range(len(matrix)):
print('Iter: ',j)
print('Before matrix: ',matrix)
sum+=((-1)**j)*matrix[0][j]*determinant(minor(j,matrix))#вот после этой строки удаляется элемент
print('After matrix: ',matrix)
print('Det: ',sum)
return sum
и вот что получаю в логах:
Matrix: [[1, 3], [2, 5]]
Iter: 0
Before matrix: [[1, 3], [2, 5]]
Major: [[1, 3], [2, 5]]
Minor: [[5]]
Matrix: [[5]]
Det: 5
After matrix: [[1, 3], [5]]
Iter: 1
Before matrix: [[1, 3], [5]]
Major: [[1, 3], [5]]
Traceback (most recent call last):
...
line 9, in minor
row.pop(i)
IndexError: pop index out of range
То есть, в итоге, на первой же итерации после строки sum+=((-1)**j)*matrix[0][j]*determinant(minor(j,matrix)) у меня матрица [[1,3],[2,5]] чудесным образом превращается в [[1,3],[5]], при том, что внутри функции minor я специально работаю с копией. Кто-нибудь может объяснить, как это происходит?
Ответы (2 шт):
Так происходит, потому что на первой же итерации def minor(i,m): возвращает major, а major при этом равен Minor: [[5]] из ваших же логов. Далее вы вызываете determinant и передаёте результат minor, то есть [[5]]. После этого у вас Matrix: [[5]].
Решения можно придумать разные, но если вы хотите решать всё в функции determinant, вы не должны вызывать её рекурсивно. Кроме данной проблемы, у вас также каждый раз будет обнуляться sum.
Большое спасибо @CrazyElf за подсказку. Действительно, в определении функции minor попытка не изменить передаваемый массив m копированием major=m.copy() дает не интуитивный результат, а именно:
- изменения первого слоя
majorтипаmajor.pop()не изменяют передаваемый массив - изменения второго слоя
majorтипаmajor[i].pop()изменяют вложенные массивы передаваемого массива
из за этого после minor(0,[[1,2],[3,4]]) не удаляется нулевая строка, но удаляется нулевой элемент первой строки, и в итоге передаваемый массив превращается в [[1,2],[4]] и далее возникает ошибка.
Тривиальным на мой взгляд является замена копии исходного массива на массив с копиями вложенных массивов: major=[x.copy() for x in m]:
def determinant(matrix):
def minor(i,m):
major=[x.copy() for x in m]
major.pop(0)
for row in major:
row.pop(i)
return major
if len(matrix)==1:
return matrix[0][0]
sum=0
for j in range(len(matrix)):
sum+=((-1)**j)*matrix[0][j]*determinant(minor(j,matrix))
return sum
Однако работая с большими вложенностями, уместнее использовать указанную @CrazyElf библиотеку from copy import deepcopy