2016-07-31 32 views
0

我想列出正方形列表。我可以用下面的代碼做到這一點:使用cons/car vs追加在球拍中創建列表

(define (makelistsq n) 
    (define outlist '()) 
    (for ((i n)) 
    (set! outlist (append outlist (list (* i i)))) 
    ) 
    outlist 
) 

(makelistsq 5) 

輸出:

'(0 1 4 9 16) 

然而,我所看到的,往往利弊和汽車關鍵字用於創建並添加到列表中。這種方法與上面的附加方法相比有什麼優勢嗎?所以,跟上面的更好或者相同:

(define (makelistsq2 n) 
    (define outlist '()) 
    (for ((i n)) 
    (set! outlist (cons (* i i) outlist)) 
    ) 
    (reverse outlist) 
) 

感謝您的回答/評論。

編輯:Cons element to list vs cons list to element in Scheme此頁面上應提到的是全部採用追加的是錯誤的:

對於那些需要在最後 添加一個元素(相信我罕見的情況下,這樣做一般意味着你認爲 算法錯誤)你可以使用追加

+2

我看到你在努力獲得計劃的竅門。請抓住一本書(SICP,如何設計程序,小Schemer)並閱讀,直到您掌握在Scheme中編寫代碼的方式。到目前爲止,您正在嘗試像編程語言一樣編寫過程,並且在學習Lisp時絕對不是這樣。 –

回答

4

我不會重複我自己的答案:P。是的,使用append通常是構建輸出列表的錯誤方法。但是你的兩個實現看起來都不錯 - 大部分時間,你必須忘掉set!和循環。

遞歸是要走的路,使用cons和(如有必要)reverse最後是建立列表的首選方式。事實上,在這個問題的功能,可以更簡潔地表示使用內置的程序,而這個寫函數式代碼時是推薦的方式:

(define (makelistsq2 n) 
    (map (lambda (x) (* x x)) 
     (range n))) 

爲了完整起見,讓我們看看我們如何會編寫程序從零開始,使用cons來構建輸出 - 對於那些罕見的場合,當沒有內置的程序來滿足你的需要時。這會產生一個遞歸的過程中,注意在這裏我們去從零到n-1

(define (makelistsq2 n) 
    (define (helper i) 
    (if (= i n) 
     '() 
     (cons (* i i) 
       (helper (add1 i))))) 
    (helper 0)) 

上述解決方案是好的,完全適用於小名單。如果(且僅當)輸出列表很大,則可能需要使用尾遞歸來構建它;這是更有效,因爲它不需要迭代額外的內存 - 我們將使用一個名爲let,並注意這會產生一個反覆的過程,從n-1爲零打算:

(define (makelistsq2 n) 
    (let loop ((i (sub1 n)) (acc '())) 
    (if (negative? i) 
     acc 
     (loop (sub1 i) (cons (* i i) acc))))) 

無論哪種實現你選擇,結果如預期:

(makelistsq2 5) 
=> '(0 1 4 9 16) 
+0

如果只發送一個整數來指示所需的高級方塊(從0開始),您該如何編碼?因此,我需要調用函數(makelistsq3 5)來獲得'(0 1 4 9 16)。 – rnso

+0

@rnso你去,三種不同風格的解決方案 –

+0

太棒了。你也可以留下以前的代碼,讓每個人都受益。 – rnso

2

cons是一對的構造函數。列表不是別的,而是由空列表()終止的cons鏈。

append是在實現中使用cons的函數。下面是一個雙參數追加執行:

(define (append lst1 lst2) 
    (if (null? lst1) 
     lst2 
     (cons (car lst1) 
      (append (cdr lst1) lst2)))) 

在純英文它使每對lst1的一雙新的,然後再連接LST2。這並不是非常有效,因此在第一個例子中,除了您爲每個步驟明確做出的一個元素列表之外,它必須生成一個4元素,3元素和2元素列表。

使用列表時,按從頭到尾的順序進行迭代,但創建列表是從頭到尾進行的。通常不可能做相反的事情,因此最終需要扭轉結果,但在您的情況下,倒計數而不是倒計時很容易。

(define (make-square-list end) 
    (let loop ((n (sub1 end)) (acc '())) 
    (if (< n 0) 
     acc 
     (loop (sub1 n) 
       (cons (* n n) acc))))) 

隨着高階函數就可以消除樣板,但#!racket有一個叫作for/list甚至更​​短的代碼的替代品。

(define (make-square-list end) 
    (for/list ((n (range end))) 
    (* n n))) 

for/list是基本相同map但作爲一種特殊形式。

0

我的版本:

#lang racket 

(define (make-square-list n) 
    (let loop ([count 1] 
      [result_list '()]) 
    (if (<= count n) 
     (loop (add1 count) (cons (* count count) result_list)) 
     (reverse result_list)))) 

(make-squqre-list 10) 

(1 4 9 16 25 36 49 64 81 100)

+0

對於內部函數是「define」還是「let」? (請參閱上面的答案中的「define(helper ..」函數,這與您的fn非常相似) – rnso

+0

我更喜歡使用let來定義內部函數。 – simmone