考虑一个由节点和邻居组成的图表:
(defparameter *graph* '((A (B C D))
(B (A C E))
(C (A B D E))
(D (A C E))
(E (B C D))))
...以及每个节点的一组标签:
(defparameter *values* '((A 1)
(B 2)
(C 3)
(D 2)
(E 1)))
我正在尝试编写一个函数来评估该格式的图形,并确定相邻节点是否具有相同的标签。如果我用C ++或Java编写这个函数,那么函数的迭代版本的逻辑可能如下所示:
(defun evaluate-label (graph values)
;; for every node in graph
;; for every adjoining node
;; if (node.value == adjoiningNode.value)
;; return false
;; return true
)
...但我不确定哪种逻辑更适合Lisp,更不用说如何编写代码了。
所以,有两个问题:
cond
。 every
对此问题有用吗?我们可以轻松地执行此操作而无需使用lambda表达式吗?提前感谢您的任何反馈!
答案 0 :(得分:3)
良好的编程的一个重要方面,无论语言如何,都是良好的抽象。有时,这可能是一个品味问题,但这里是一个试图对这个问题应用一些抽象的例子。获得图形和值后,可以定义一个返回节点值的节点值函数。然后你可以将你的问题短语
图表中是否存在与其邻居之一具有相同节点值的节点?
使用某些:
写这个并不难(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(some #'(lambda (node-descriptor)
(destructuring-bind (node neighbors)
node-descriptor
(find (node-value node) neighbors
:key #'node-value)))
graph)))
(adjacent-values-p '((a (b c)))
'((a 1) (b 2) (c 1)))
;=> C
(adjacent-values-p '((a (b c)))
'((a 1) (b 2) (c 3)))
;=> NIL
尽管如此,即使在某种意义上可能更多的是Lisp-y,但使用 dolist 进行显式迭代来编写它可能同样有意义:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(dolist (node-descriptor graph)
(destructuring-bind (node neighbors) node-descriptor
(when (member (node-value node) neighbors :key #'node-value)
(return t))))))
这可以通过循环更好,它支持一些解构:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(loop for (node neighbors) in graph
thereis (find (node-value node) neighbors :key #'node-value))))
所有这些版本都可以从例如存储值中受益。用于更快检索的哈希表。这是否有意义取决于您的需求,应用程序域等。否则您将检索边标签O(2×| E |),每次执行O(| V |)遍历。例如:
(let ((table (make-hash-table)))
(flet ((node-value (node)
(multiple-value-bind (value presentp)
(gethash node table)
(if presentp value
(setf (gethash node table)
(cadr (assoc node values)))))))
;; ...
))
通过在需要之前不查找节点值来缓存“按需”。但是,由于应该需要每个节点值(假设提供的值列表不包含任何额外节点),最好只在开头填充表。然后,您不必在以后进行任何检查,只需遍历值列表一次。因此:
(defun adjacent-values-p (graph values &aux (table (make-hash-table)))
(loop for (node value) in values
doing (setf (gethash node table) value))
(flet ((node-value (node)
(gethash node table)))
;; ...
))