如何无损地交换普通lisp中二维数组中的两行

时间:2019-02-23 19:20:16

标签: arrays multidimensional-array functional-programming common-lisp

我正在尝试在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))))

我看过其他一些事情,但是复制数组的某些方法似乎有些overly complicated。预先感谢您的任何建议。

P.S。我宁愿不使用任何外部图书馆(非常抱歉推荐亚历山大的人)。

2 个答案:

答案 0 :(得分:4)

在下面,您无需复制,只需将变量(copy)绑定到现有值(绑定到matrix的值)上即可。

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

从另一个答案中可以看出,您可以使用Alexandria库来复制数组而没有太多的复杂性。例如:

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

在您的情况下,如果导入符号,则只需编写:

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

如果只交换行而不修改行的内容,则可以将矩阵定义为向量序列。您将共享相同的行,但顺序不同(如果需要更改值,则可以复制向量)。

答案 1 :(得分:2)

在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))))))

实际上,这会将原始数组转换为列表块,并从这些列表开始重建一个新数组。