Как поменять местами два ряда в двумерном массиве в общем лиспе неразрушающим - PullRequest
0 голосов
/ 23 февраля 2019

Я пытаюсь поменять две строки в двумерном массиве в 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))))

Есть некоторые другие вещи, на которые я смотрел, но некоторые способы копирования массива кажутся чрезмерно сложными .Заранее благодарен за любой совет.

PS Я предпочитаю не использовать какие-либо внешние библиотеки (очень жаль тому, кто рекомендовал Александрию).

Ответы [ 2 ]

0 голосов
/ 24 февраля 2019

Копировать массив в 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))))))

На практике это преобразует исходный массив в блоки списков и перестраивает новый массив, начиная с этих списков.

0 голосов
/ 23 февраля 2019

Здесь ниже вы не делаете копию, просто привязываете переменную (copy) к существующему значению (которое привязано к matrix):

(let ((copy matrix))
  ...)

Как видно из другого ответа, вы можете использовать библиотеку Александрия для копирования массива без особых сложностей;например:

(alexandria:copy-array #2A((1 0 0)
                           (0 1 0)
                           (0 0 1)))

В вашем случае, если вы импортируете символ, достаточно написать:

(let ((copy (copy-array matrix)))
  ...)

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

...