Я пытаюсь поменять местами две строки в двумерном массиве в Common Lisp. Я нашел способ сделать это с помощью aref. Это деструктивный способ сделать это, и я хотел бы, чтобы он был более функциональным. У кого-нибудь есть идея получше?
(defun swap-rows (matrix r1 r2)
"Returns a modified matrix with two swapped rows"
(loop for i upto (1- (array-dimension matrix 1))
do (rotatef (aref copy r1 i) (aref copy r2 i))))
Я пытался сделать копию исходного массива, но он все еще меняет исходный массив. Это моя вторая попытка:
(defun swap-rows (matrix r1 r2)
"Returns a modified matrix with two swapped rows"
(let ((copy matrix))
(loop for i upto (1- (array-dimension matrix 1))
do (rotatef (aref copy r1 i) (aref copy r2 i))
finally (return copy))))
Есть и другие вещи, на которые я смотрел, но некоторые способы копирования массива кажутся несколько слишком сложный. Заранее благодарю за любой совет.
P.S. Я предпочитаю не использовать сторонние библиотеки (очень жаль человека, который рекомендовал Александрию).



Ниже вы не копируете, а просто привязываете переменную (copy) к существующему значению (которое привязано к matrix):
(let ((copy matrix))
...)
Как видно из другого ответа, вы можете использовать библиотеку Александрия для копирования массива без особых сложностей; Например:
(alexandria:copy-array #2A((1 0 0)
(0 1 0)
(0 0 1)))
В вашем случае, если вы импортируете символ, достаточно написать:
(let ((copy (copy-array matrix)))
...)
Если вы меняете местами только строки без изменения их содержимого, возможно, вы можете определить матрицы как последовательности векторов. Вы бы разделили одни и те же строки, но в другом порядке (и если вам нужно изменить значения, вы можете скопировать векторы).
Копировать массив в Common Lisp не очень просто, и я думаю, это связано с тем, что массивы в этом языке представляют собой структуры данных, особенно подходящие для программирования с побочными эффектами, а не для программирования без побочных эффектов (или функционального). Как указал @coredump, если вы предпочитаете использовать программирование без побочных эффектов, вам, вероятно, следует использовать другие структуры данных, такие как список списков или последовательности векторов.
Если вы хотите придерживаться массивов, вот альтернативный способ сделать вашу копию (не очень простой и эффективный!):
(defun swap-rows (matrix r1 r2)
"returns a copy of matrix with rows r1 ≤ r2 swapped"
(let* ((rows (array-dimension matrix 0))
(cols (array-dimension matrix 1)))
(flet ((get-rows (from-r to-r)
"get block of matrix from row from-r to row to-r excluded"
(loop for i from from-r below to-r
collect (loop for j from 0 below cols
collect (aref matrix i j)))))
(make-array
(list rows cols)
:initial-contents
(append (get-rows 0 r1)
(get-rows r2 (1+ r2))
(get-rows (1+ r1) r2)
(get-rows r1 (1+ r1))
(get-rows (1+ r2) rows))))))
На практике это преобразует исходный массив в блоки списков и перестраивает новый массив, начиная с этих списков.