我正在尝试在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。我宁愿不使用任何外部图书馆(非常抱歉推荐亚历山大的人)。
答案 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))))))
实际上,这会将原始数组转换为列表块,并从这些列表开始重建一个新数组。