2011-04-20 31 views
7

是否可以這樣做?假設我想獲得列表的最後一個元素,我將創建一個變量i = 0,並將其增加,直到它等於長度。任何想法?一個例子將不勝感激。如何在Scheme函數內聲明一個變量?

謝謝,

+1

你有什麼算法來獲取最後一個元素? – 2011-04-20 16:59:50

+0

@larsmans:遍歷列表直到「i」等於長度?在計劃中這聽起來合理嗎? – Chan 2011-04-20 23:04:08

+0

這聽起來很浪費,因爲你遍歷列表兩次;第一次計算長度。該算法將是線性時間(不像@ sepp2k所假設的那樣是二次的),而是兩次通過而不是慣用的。 – 2011-04-21 09:00:14

回答

11

有幾種方法來聲明一個變量;最乾淨的一個是let

(let ((x some-expr)) 
    ; code block that uses x 

但你並不需要它來獲取列表的最後一個元素。只需使用遞歸:

(define (last xs) 
    (if (null? (cdr xs)) 
    (car xs) 
    (last (cdr xs)))) 

注意:如果你願意,你可以使用一個變量來緩存cdr的結果:

(define (last xs) 
    (let ((tail (cdr xs))) 
    (if (null? tail) 
     (car xs) 
     (last tail)))) 
+0

非常感謝,非常好的解決方案!順便說一句,我對上面的if語句有點困惑。 'last tail'屬於'if'還是單獨聲明?我們如何區分? – Chan 2011-04-20 23:13:00

+1

@Chan:'(last tail)'是'if'表達式的其他部分。你可以通過parens和我使用縮進來判斷。 – 2011-04-21 08:59:02

3

是的,它可以定義在方案中的局部變量,或者使用let或者define裏面的一個函數。使用set!,也可以像您想象的那樣重新分配一個變量。

這就是說,你可能不應該這樣解決你的問題。在計劃中,當你不需要時避免set!是一種很好的做法(在這種情況下,你肯定不需要)。進一步遍歷使用索引的列表通常是一個壞主意,因爲方案的列表是鏈接列表,因此隨機訪問O(n)(使last的功能與您想實現的功能相同)。

因此,一個沒有索引的簡單遞歸實現將比你打算做的更具慣用和更快,因此更可取。

+1

謝謝。我的問題是從列表中刪除最後一個元素。我可以改變列表,然後刪除第一個元素,但是效率太低了。與其他傳統語言如C或C++相比,Scheme中的思考是完全奇怪的。 – Chan 2011-04-20 23:05:49

+0

除了使用'set!'之外,還有其他方法可以在Scheme中重新定義一個變量嗎? – 2013-06-21 00:42:22