Сортировка сложного массива numpy, присвоение значения по значению и по ссылке

#python #numpy #variable-assignment

#python #numpy #присвоение переменной

Вопрос:

Я столкнулся с интересной проблемой, которая, я думаю, должна что-то делать с присвоением по значению и по ссылке с использованием массивов numpy. Допустим, я хочу отсортировать массив numpy, используя классическую пузырьковую сортировку. Если я не включаю в функцию numpy.copy или copy.deepcopy заменяемого значения (т.Е. Временной переменной), сортировка не работает (разница между bubbleSortComplex, bubbleSortComplex2). Я заметил проблему при сортировке сложных массивов по их значению abs, однако позже обнаружил, что проблема также связана с простыми ndarrays. Хотя я вроде бы нашел ответ на свою проблему, я не понимаю, почему это происходит. Я знаю, что в этом случае я могу использовать встроенную функцию, например, numpy.sort, но я обнаружил, что эта проблема является более сложной и проблематичной только для простого присвоения комплексного значения переменной.

 import numpy as num
import copy as cp

def main():
    nlist = [14,46,43,27,57,41,45,21,70]

    nlist2 = num.zeros((5,1),dtype=complex)
    nlist2[0] = num.complex(1,2); nlist2[1] = num.complex(3,4); nlist2[2] = num.complex(2,7)
    nlist2[3] = num.complex(3,9); nlist2[4] = num.complex(1,3)

    nlist3 = cp.deepcopy(nlist2)

    nlist4 = num.zeros((5,1))
    nlist4[0] = 14; nlist4[1] = 46; nlist4[2] = 43; nlist4[3] = 27; nlist4[4] = 57

    nlist5 = cp.deepcopy(nlist4)

    # print original arrays
    print(nlist); print(" ")    # prints [14, 46, 43, 27, 57, 41, 45, 21, 70]
    print(nlist2); print(" ")   # prints [[1. 2.j] [3. 4.j] [2. 7.j] [3. 9.j] [1. 3.j]]
    print(nlist3); print(" ")   # prints [[[1. 2.j] [3. 4.j] [2. 7.j] [3. 9.j] [1. 3.j]]
    print(nlist4); print(" ")   # prints [[[14.] [46.] [43.] [27.] [57.]]
    print(nlist5); print(" ")   # prints [[[14.] [46.] [43.] [27.] [57.]]

    # Sorting arrays and printing results
    bubbleSort(nlist); print(nlist); print(" ")             # prints [70, 57, 46, 45, 43, 41, 27, 21, 14]

    bubbleSortComplex(nlist2); print(nlist2); print(" ")    # prints [[3. 9.j] [3. 9.j] [3. 9.j] [3. 9.j] [1. 3.j]]

    bubbleSortComplex2(nlist3); print(nlist3); print(" ")   # prints [[3. 9.j] [2. 7.j] [3. 4.j] [1. 3.j] [1. 2.j]]

    bubbleSort(nlist4); print(nlist4)                       # prints [[57.] [57.] [57.] [57.] [57.]]

    bubbleSortComplex2(nlist5); print(nlist5); print(" ")   # prints [[57.] [46.] [43.] [27.] [14.]]

def bubbleSort(nlist):
    for passnum in range(len(nlist)-1,0,-1):
        for i in range(passnum):
            if nlist[i 1]>nlist[i]:
                temp = nlist[i]
                nlist[i] = nlist[i 1]
                nlist[i 1] = temp

def bubbleSortComplex(nlist):
    for passnum in range(len(nlist)-1,0,-1):
        for i in range(passnum):
            if num.abs(nlist[i 1])>num.abs(nlist[i]):
                temp = nlist[i]
                nlist[i] = nlist[i 1]
                nlist[i 1] = temp

def bubbleSortComplex2(nlist):
    for passnum in range(len(nlist)-1,0,-1):
        for i in range(passnum):
            if num.abs(nlist[i 1])>num.abs(nlist[i]):
                temp = cp.deepcopy(nlist[i])
                nlist[i] = nlist[i 1]
                nlist[i 1] = temp

if __name__ == '__main__':
    main()
 

Ответ №1:

Вы bubbleSortComplex даете неверный результат по очень простой, но, вероятно, более сложной для определения причине.

Вам не нужно выполнять deepcopy , nlist[i] чтобы заставить его работать, но вам нужно быть осторожным с вводом в функцию.

Этот код nlist2 = num.zeros((5,1)) создает 2d-массив (вектор столбцов). В данном случае nlist[i] на самом деле это не число, а изменяемый массив, содержащий одно значение. Вы можете вызвать type(nlist[i]) , чтобы увидеть, что вывод numpy.ndarray .

Если вы измените инициализацию массива на nlist2 = np.zeros(5 ,dtype=complex) , тип nlist[i] будет неизменяемым numpy.complex128 , и ваш код будет работать просто отлично.

 nlist2 = np.zeros(5 ,dtype=complex)
nlist2[0] = np.complex(1,2); nlist2[1] = np.complex(3,4); nlist2[2] = np.complex(2,7)
nlist2[3] = np.complex(3,9); nlist2[4] = np.complex(1,3)

def bubbleSortComplex(nlist):
    for passnum in range(len(nlist)-1,0,-1):
        for i in range(passnum):
            if np.abs(nlist[i 1])>np.abs(nlist[i]):
                temp = nlist[i]
                nlist[i] = nlist[i 1]
                nlist[i 1] = temp
                
bubbleSortComplex(nlist2)
print(nlist2)
 

будет печатать [3. 9.j 2. 7.j 3. 4.j 1. 3.j 1. 2.j] .

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

Комментарии:

1. Спасибо за ваше объяснение. Хотя я совсем новичок в python (работал в основном в Matlab), и я понял, что я понимаю идею указателей из моего небольшого опыта работы с C и ООП, я не мог придумать разумного объяснения, почему это работает не так, как предполагалось. Другим моим дальнейшим объяснением после этого поста было то, что я думал, что, возможно numy.ndarrays , всегда считаются изменяемыми , и поэтому мне следует пересмотреть возможные недостатки во всех моих кодах. В любом случае, спасибо вам за ваш ответ.