2013-05-09 50 views
1

如果我有一個S表達,例如「(1 2(3)(4(5))6 7),我將如何轉換到這樣(1 2列表3 4 5 6 7)?我基本上需要從s表達式中提取所有原子。是否有內置的函數可以幫助我做到這一點?轉換的表情到列表方案

(define (convert-to-list s) ...) 

到目前爲止,我的算法是,如果第一個元素是一個原子將它附加到列表上。如果第一個元素是一個列表,然後獲得該元素的汽車,然後調用與函數的函數(轉換到列表),所以它抓住了遞歸的基本情況。並將其轉換列表上調用的列表的cdr附加到它的車上。我試圖從計算機程序的結構和解釋中教授自己的方案,我只是在嘗試隨機的東西。以遞歸方式做這件事證明比我預期的更困難。

+6

的[僅使用「的小策士」的形式拼合列表]可能的複製(http://stackoverflow.com/questions/7313563/flatten-a-list-using-only-小型策略者的形式)和[球拍/方案展開說明](http://stackoverflow.com/questions/13547965/racket-scheme-flatten-explanations)。 (這兩篇文章都提到了'flatten'的高質量實現,它們不使用'append'。Disclosure:我寫了一個這樣的實現。) – 2013-05-09 02:58:19

回答

1

你的算法不看壞,它只是缺少了一兩步。

(define (flatten lst) ; 'flatten' is a better name for this function IMO 
    (cond 
    ((null lst) nil) 
    ;; Don't worry that I'm calling (flatten (cdr lst)) without any checking; 
    ;; the above case handles it 
    ((atom (car lst)) ; The car's okay 
    (cons (car lst) (flatten (cdr lst)))) 
    ((cons? (car lst)) ; The car still needs flattening; note the use of 
         ; 'append' here (the car-list may have any number of elements) 
    (append (flatten (car lst)) (flatten (cdr lst)))))) 

(flatten (car lst))呼叫處理與所述第一元件和所述(flatten (cdr lst))調用遞歸處理列表的其餘部分之間,將輸入表結束平面列表(即,沒有任何元素conses之外)。

警告:我不是一個計劃大師;上面的代碼中可能有錯誤)

1

你的情況應包括空單,原子(轎廂S)是一個原子,和(汽車s)是一個列表。

這個工作,雖然我列出了一個列表追加函數,因爲我不記得內置函數是什麼。適用於球拍高級學生。

(define (list-glue left-list right-list) 
    (cond 
    ((null? left-list) right-list) 
    (else (cons (car left-list) (list-glue (cdr left-list) (right-list)))))) 

(define (convert-to-list s) 
    (cond 
    ((null? s) '()) 
    ((not (list? s)) (cons s (quote()))) 
    ((not (list? (car s))) (cons (car s) (convert-to-list (cdr s)))) 
    (else 
     (list-glue 
     (convert-to-list (car s)) 
     (convert-to-list (cdr s)))))) 
4

字面上回答你的問題,「是否有一個內置的功能,以幫助我做到這一點?」,在球拍肯定是有的。 flatten完全是這樣的:「將一對任意的S表達式結構變爲一個列表。」

Examples: 
> (flatten '((a) b (c (d) . e)())) 
'(a b c d e) 
> (flatten 'a) 
'(a) 

但是這是一個很好的鍛鍊思考如何你會寫自己flatten

克里斯小丑,年輕的評論有一個鏈接,以一種優雅的方式。如果她發佈了這個答案,而不是作爲評論,我建議將她的答案標記爲已接受,而不是我的答案。 :)

1

現在,如果你想要更快的實施,你根本不需要append

的想法是繞過你會追加到作爲一個參數是什麼。我稱之爲尾巴。 如果你有一個空的s-exp,你只需要返回尾部,因爲沒有什麼要添加到尾部。

我已經得到了代碼,flatflat2,其中flat使用match聲明,事情球拍,和flat2只是使用cond,我覺得這有點難以閱讀,但我提供它的情況下,你的避風港沒看過match呢。

#lang racket 


(define (flat s-exp tail) 
    (match s-exp 
     ['() tail] 
     [(cons fst rst) 
      (let ([new-tail (flat rst tail)]) 
      (flat fst new-tail))] 
     [atom 
      (cons atom tail)])) 

(define (flat 
    (cond 
    [(empty? s-exp) tail] 
    [(list? s-exp) 
    (let* ([fst (first s-exp)] 
      [rst (rest s-exp)] 
      [new-tail (flat]) 
     (flat fst new-tail))] 
    [#t 
    (cons s-exp tail)])) 

要使用它們,叫他們像這樣(flat '(1() (2 (3)) 4) '()) ===>'(1 2 3 4)。 您需要提供空列表供他們開始。

0

這可以簡單地通過遞歸子列表和休息列表完成。你可以看到這段代碼讀起來有多容易。喜歡這樣:

(define (convert-to-list list) 
    (if (null? list) 
     '() 
     (let ((next (car list)) 
      (rest (cdr list))) 
     (if (list? next) 
      (append (convert-to-list next) (convert-to-list rest)) 
      (cons next (convert-to-list rest)))))) 
> (convert-to-list '(a b c)) 
(a b c) 
> (convert-to-list '((a b) (((c d) e f) g h) i j)) 
(a b c d e f g h i j) 
>