良好的編程的一個重要方面,無論語言如何,都是很好的抽象。有時候,這可能是一個有趣的問題,但這裏有一個例子試圖對這個問題應用一些抽象。一旦獲得了圖形和值,就可以定義一個返回節點值的節點值函數。然後你可以將你的問題描述爲
有沒有某個節點的圖形與其鄰居有相同的節點值?
這是不是太難用寫一些:
(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))))
所有這些版本可以從存儲的值,e.g受益,。一個快速檢索的散列表。這是否有意義取決於您的需求,應用領域等。否則,您將檢索邊標籤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)))
;; ...
))
使用'DOLIST'宏,您可以迭代列表。像「RETURN」或「RETURN-FROM」這樣的東西也可能有用。祝你好運! – 2014-09-28 22:09:05
@Rainer Joswig - 使用'DO'或其一個變體絕對是一種選擇。我不禁想到,必須有更多的「Lispy」寫這個函數的方式,例如用一個高階函數來遍歷圖的節點。這就是我在這裏尋找的 - 本身並不是一種解決方案,而是一種適合這種語言的方法。 – jda 2014-09-29 00:04:11
@jda看看使用'一些'。 – malisper 2014-09-29 02:44:09