下面的代码是对Paul的ANSI Common (前例)中的练习的回答。4.1)。挑战是将数组旋转90度。我找到了一个示例解决方案,我在下面作了评论。
这似乎没问题,我很喜欢学习如何使用do,但在这种特殊情况下,它实际上似乎比用于处理2d数组的家族c样式嵌套的循环更加冗长。我想知道下面的款式是好的还是可以改进的?
答案是循环宏吗?在学习的同时,我正在避免这种情况,直到我更好地掌握了基本知识。但却不想染上坏习惯。因此,这个关于风格的问题与下文有关。
(defun quarter-turn (arr)
(let* ((dim (array-dimensions arr)) ; let* sets sequentially, not in parallel.
(row (first dim))
(col (second dim))
(n row) ; initialise n to row, just to organise
new-arr) ; shorthand for (new-arr nil)
(cond ((not (= row col))
(format t "The arg is not a square array.~%"))
(t (setf new-arr (make-array dim :initial-element nil))
(do ((i 0 (+ i 1))) ; Q. surprisingly, lisp's 'do' here looks more
((= i n)) ; verbose than c-style 'for'. Is this good style?
(do ((j 0 (+ j 1)))
((= j n))
(setf (aref new-arr j i) (aref arr (- n i 1) j))))
new-arr))))以上代码的来源:http://www.cs.uml.edu/~lhao/ai/lisp/ansi-common-lisp/solution-ch04.htm
发布于 2019-04-19 17:26:30
关于您的代码的一些评论:
n副本?如果您想更加简洁,可以在n和m中使用row和col (我不喜欢它们,因为它们是单数名称,而它们代表行数和列数)。new-arr,然后在测试的正方形之后分配它呢?不要在需要的情况下多次使用let,在需要的时候引入变量。assert而不是cond来检查是否有正确的参数:通过这种方式,您可以给用户纠正参数的机会,并产生更短、更易读的代码。nil?do可以返回结果,以避免函数的最后一行。1+,而不是1求和。因此,在这第一组注释之后,函数可以重写为:
(defun quarter-turn (arr)
"rotate a square matrix 90° clockwise"
(let* ((dim (array-dimensions arr))
(n (first dim))
(m (second dim)))
(assert (= n m) (arr) "The argument is not a square array.")
(let ((new-arr (make-array dim)))
(do ((i 0 (1+ i)))
((= i n) new-arr)
(do ((j 0 (1+ j)))
((= j n))
(setf (aref new-arr j i) (aref arr (- n i 1) j)))))))正如您已经注意到的,在本例中,do比loop更冗长。我认为,在这种情况下,它们或多或少是等同的(只是个人意见)。我更喜欢loop表单,这不仅是因为在我看来它略显简洁,而且还因为用两种嵌套loop表单的术语来考虑二维数组的经典嵌套循环更“自然”:
(defun quarter-turn (arr)
"rotate a square matrix 90° clockwise"
(let* ((dim (array-dimensions arr))
(n (first dim))
(m (second dim)))
(assert (= n m) (arr) "The argument is not a square array.")
(let ((new-arr (make-array dim)))
(loop for i below n
do (loop for j below n
do (setf (aref new-arr j i) (aref arr (- n i 1) j))))
new-arr)))https://codereview.stackexchange.com/questions/217739
复制相似问题