【发布时间】:2015-02-22 04:30:12
【问题描述】:
我正在尝试编写一个函数,该函数采用名为nodes 的用户定义对象列表来生成它们之间的连接。每个node 对象都有一个用于其唯一编号('num')的槽和一个用于充当节点之间的边('edges')的数字列表的槽。 +max-edges+ 是一个整数,它定义了边缘配对尝试的次数,+max-rooms+ 是传递给函数的节点列表中的节点数(并且始终小于 50)。
这里有两个版本的函数试图解决这个问题:
(defun connect-nodes (node-list)
"Given a NODE-LIST, repeats for +MAX-EDGES+ amount of times
to alter NODE-LIST in-place to connect randomly generated edges to nodes."
(loop repeat +max-edges+
do (let ((begin-node (random +max-rooms+))
(end-node (random +max-rooms+)))
(when (not (= begin-node end-node))
(setf (slot-value (nth begin-node node-list) 'edges)
(cons end-node
(slot-value (nth begin-node node-list) 'edges)))
(setf (slot-value (nth end-node node-list) 'edges)
(cons begin-node
(slot-value (nth end-node node-list) 'edges))))))))
(defun connect-nodes% (node-list)
"Given a NODE-LIST, repeats for +MAX-EDGES+ amount of times
to alter NODE-LIST in-place to connect randomly generated edges to nodes."
(loop repeat +max-edges+
do (let ((begin-node (random +max-rooms+))
(end-node (random +max-rooms+)))
(when (not (= begin-node end-node))
(let ((begin-node-lst (slot-value (nth begin-node node-list) 'edges))
(end-node-lst (slot-value (nth end-node node-list) 'edges)))
(setf begin-node-lst (cons end-node begin-node-lst))
(setf end-node-lst (cons begin-node end-node-lst)))))))
(connect-nodes) 按预期工作,但最后两行在文体上似乎很长,并且查找两次为setf 的对象的槽值,我想这可能是性能问题。
(connect-nodes%) 尝试通过将位置绑定到词法范围的位置来解决双重查找,但实际上并没有就地更改节点列表参数。没有进行任何更改,因为let 绑定(begin-node-lst 和 end-node-lst)中的每个位置都仅在词法上绑定,并且在 setfs 之后超出范围。
所以我要求澄清几点:
- 我对为什么第二个函数无法更改参数列表的理解是否正确?
- 第一个函数在风格上是否正确?有没有更好的方法来编写这个函数,它不会为
setf两次查找槽值,或者这对于小长度列表是否可以接受?
如果您的回答中考虑到这点,我正在运行 slime + emacs + sbcl。
编辑:
多亏了我的问题答案中的建议,我最终得到了 connect-nodes 函数的列表版本。我正在开发一个适用于向量的版本,因此这个版本的connect-nodes 是一个泛型函数的方法:
(defmethod connect-nodes ((node-list list))
"Given a NODE-LIST, repeats for +MAX-EDGES+ amount of times
to alter NODE-LIST in-place to connect randomly generated edges to nodes."
(loop repeat +max-edges+
do (let ((begin-node (random +max-rooms+))
(end-node (random +max-rooms+)))
(when (not (= begin-node end-node))
(push end-node (edges (nth begin-node node-list)))
(push begin-node (edges (nth end-node node-list)))))))
【问题讨论】:
-
我得到的一般建议是:1) 使用
PUSH宏,它执行SETFing 的模式,将项目的值consed 到一个地方的列表中。 2) 当我可以直接在边槽中添加对它们的引用时,为我的对象存储数字查找键似乎很浪费。