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) 
>