1

我定义了一个矩阵,所以如果我这样做

(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]

因为 1 次运行 get-real-2d 的输出只是 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
4

4 回答 4

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-dimensionaref使用您的版本。

于 2013-09-21T11:35:43.930 回答
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))
于 2013-09-21T21:17:39.367 回答
1

这并不难,所以我宁愿让你自己弄清楚,但这里有一些技巧可以制作一个“光滑循环”的 Lisp 风格。我建议使用mapc(or mapcar) 的一个或多个实例,而不是dotimes. 如果你不习惯函数式编程,这可能会觉得很奇怪,但是一旦你习惯了它,它就会比 更容易阅读dotimes,而且你不必跟踪索引,因此可以避免错误。mapcar/mapc如果您还不熟悉它们,您真的应该学习使用它们。他们很酷。或者如果你想变得很酷:-)你可以使用递归来迭代矩阵,但我认为为此目的迭代使用mapc会更容易阅读。(但你应该学习其他工作的递归方式。如果你发现递归令人困惑——我没有理由认为你这样做,但有些人对此有麻烦——我最喜欢的教程是The Little Schemer。)

您可能还想使用其他format指令,如果它们没有足够的数字,则允许您用空格填充数字。该~%指令也可能有用。Peter Seibel 对 format 有很好的介绍

于 2013-09-21T05:46:13.727 回答
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.

于 2013-09-21T20:33:02.433 回答