我有一个矩阵定义,所以如果我这样做
(format t "~a" (get-real-2d 0 0))
它打印出第一行第一列中的元素
如果我这样做
(format t "~a" (get-real-2d a 0 1))
它打印出第一行第二列中的元素
如果我这样做
(format t "~a" (get-real-2d a 1 0))
它打印出第二行第一列中的元素。
矩阵a
看起来像这样
a =
((0 1 2)
(3 4 5)
(6 7 8))
我希望你能告诉我如何编写dotimes
循环或其他循环
尽可能少的行将使用get-real-2d
函数打印出矩阵,因此输出如下所示:
0 1 2
3 4 5
6 7 8
我只是希望你能给我看一个非常小的光滑循环,我可以用来打印矩阵,我可以在我的lisp库中使用一些真正专业的东西,比如只使用变量的矩阵。类似的东西:
(format t "~a" (get-real-2d i j))
而不是一堆:
(format t "~a" (get-real-2d 0 0))
(format t "~a" (get-real-2d 0 1))
(format t "~a" (get-real-2d 0 2))
;;;;最新编辑;;; 为了使这个简单,我打电话
(defparameter a (create-mat 3 3 +32fc1+))
创建一个3x3矩阵 - create-mat是opencv的cvCreateMat的包装器
repl上该命令的输出是
(defparameter a (create-mat 3 3 +32fc1+))
A
CL-OPENCV> a
#.(SB-SYS:INT-SAP #X7FFFD8000E00)
i / e变量a是指向3x3矩阵的指针
然后我跑
(defparameter data (cffi:foreign-alloc :float :initial-contents
'(0.0f0 1.0f0 2.0f0 3.0f0 4.0f0 5.0f0 6.0f0 7.0f0 8.0f0)))
为矩阵创建数据 - 我接下来将分配给矩阵
repl上该命令的输出是
CL-OPENCV> (defparameter data (cffi:foreign-alloc :float :initial-contents
'(0.0f0 1.0f0 2.0f0 3.0f0 4.0f0 5.0f0 6.0f0 7.0f0 8.0f0)))
DATA
CL-OPENCV> data
#.(SB-SYS:INT-SAP #X7FFFD8000E40)
i / e变量a是指向数据插入矩阵的数据指针
然后我打电话给..(set-data a data 12) to add the data to the matrix - set-data is a wrapper for opencv's cvSetData
所以现在当我运行 - (get-real-2d是opencv的cvGetReal2d的包装器)
(get-real-2d a 0 0) it gets the element of matrix a at row 0 col 0 which is 0.0d0
repl上该命令的输出是
CL-OPENCV> (get-real-2d a 0 0)
0.0d0
现在我跑的时候
(get-real-2d a 0 1) it gets the element of matrix a at row 0 col 1 which is is 0.0d0
repl上该命令的输出是
CL-OPENCV> (get-real-2d a 0 1)
1.0d0
当我运行此循环时
(dotimes (i 3)
(dotimes (j 3)
(format t "~a~%" (get-real-2d a i j))))
repl上该命令的输出是
CL-OPENCV> (dotimes (i 3)
(dotimes (j 3)
(format t "~a~%" (get-real-2d a i j))))
0.0d0
1.0d0
2.0d0
3.0d0
4.0d0
5.0d0
6.0d0
7.0d0
8.0d0
NIL
但是当我尝试你的方法@Svante
时(dotimes (i 3)
(dotimes (j 3)
(format t "~{~{~a~^ ~}~%~}" (get-real-2d a i j))))
我收到错误:
The value 0.0d0 is not of type LIST.
[Condition of type TYPE-ERROR]
因为get-real-2d的1次运行的输出只是1次浮点数i / e
CL-OPENCV> (get-real-2d a 0 0)
0.0d0
有了这些信息,你可以帮我打印矩阵,看起来像这样吗
0.0d0 1.0d0 2.0d0
3.0d0 4.0d0 5.0d0
6.0d0 7.0d0 8.0d0
答案 0 :(得分:5)
您可以直接在format
指令中执行此操作。格式说明~{
和~}
会进入列表结构。
(format t "~{~{~a~^ ~}~%~}" matrix)
外部~{
~}
对遍历矩阵的第一级,因此内部的指令一次只能看到一行。内部~{
~}
对遍历每一行,以便内部的指令一次看到一个元素。 ~A
打印该元素。 ~^
和~}
之间的部分仅在循环体的执行之间打印,而不是在结尾处执行。 ~%
会发出#\Newline
。
按要求编辑
请注意,~{
~}
会替换循环,并且我将变量命名为matrix
,而不是element
。你需要将整个矩阵放在那里,它应该是嵌套列表的形式。我从您a
((0 1 2) (3 4 5) (6 7 8))
(format t "~{~{~a~^ ~}~%~}" a)
的陈述中推断出这一点。所以,dotimes
。
如果矩阵不是以嵌套列表的形式而是某种类型的数组,那么你真的需要遍历索引。首先,嵌套的(fresh-line)
(dotimes (i (array-dimension array 0))
(dotimes (j (array-dimension array 1))
(format t "~a " (aref array i j)))
(terpri))
表单应该足够了:
array-dimension
我不知道您的矩阵如何映射到数组,因此您必须将aref
和{{1}}替换为您的版本。
答案 1 :(得分:1)
这并不难,所以我宁愿把它留给你弄清楚,但这里有一些提示,以制作一个“光滑的循环”Lisp风格。我会建议mapc
(或mapcar
)的一个或多个实例,而不是dotimes
。如果你不习惯函数式编程,这可能会有点奇怪,但是一旦你习惯了它,它比dotimes
更容易阅读,你不必跟踪索引,所以它可以避免错误。如果你还不熟悉它们,你真的应该学会使用mapcar/mapc
。他们很酷。或者,如果你想真的很酷:-)你可以使用递归迭代矩阵,但我认为为此目的,使用mapc
进行迭代将更容易阅读。 (但是你应该学习其他工作的递归方式。如果你发现递归令人困惑 - 我没有理由认为你这么做,但是有些人有麻烦 - 我最喜欢的教程是 The Little Schemer 。)
您可能还想使用其他format
指令,如果数字没有足够的数字,则允许您使用空格填充数字。 ~%
指令也可能有用。彼得塞贝尔有一个非常好的introduction to format。
答案 2 :(得分:1)
您的问题可以通过两种方式理解,这就是为什么它有两个解决方案:
定义打印矩阵类型对象的方法(在这种情况下,它可以使用有关矩阵内部结构的知识):
(defmethod print-object ((matrix matrix) stream)
(format stream "~{~{~a~^ ~}~%~}" matrix))
使用format
,如答案中所示。
定义可以使用对象的唯一方法的客户端函数 - get-real-2d
:
(defun print-matrix (matrix dimension-x dimension-y)
(dotimes (x dimension-x)
(dotimes (y dimension-y)
(princ (get-real-2d matrix x y))
(princ #\Space))
(princ #\Newline)))
只需使用dotimes
。
答案 3 :(得分:1)
以下是您要求的两个dotimes
循环。您需要注意的唯一事项是何时打印空格以及何时打印换行符。
(dotimes (i 3)
(dotimes (j 3)
(princ (get-real-2d a i j))
(if (< j 2)
(princ #\Space)
(terpri))))
或者,您可能希望使用format
指令进行浮点打印,以使数字始终在漂亮的列中对齐。您可以选择永不打印指数的~F
,始终打印一个指数的~E
,以及根据幅度行事的~G
。在HyperSpec中查找详细信息:http://www.lispworks.com/documentation/HyperSpec/Body/22_cc.htm。
以下是使用~F
的示例,其最大字段宽度为5和1个小数位:
(dotimes (i 3)
(dotimes (j 3)
(format t "~5,1F" (get-real-2d a i j)))
(terpri))