如果我有一个s表达式,例如'(1 2(3)(4(5))6 7),我如何将其转换为像(1 2 3 4 5 6 7)这样的列表?我基本上需要从s表达式中提取所有原子。是否有内置功能可以帮助我做到这一点?
(define (convert-to-list s) ... )
到目前为止,我的算法是,如果第一个元素是原子,则将其附加到列表中。如果第一个元素是一个列表,那么获取该元素的汽车,然后使用该函数调用该函数(convert-to-list),以便捕获递归的基本情况。并将转换为列表时调用的该列表的cdr附加到它的car。我正在尝试从计算机程序的结构和解释中自学计划,我只是尝试随机的东西。递归地做这件事证明比我预期的要困难得多。
答案 0 :(得分:4)
要字面上回答你的问题,“是否有内置功能可以帮助我这样做?”,在Racket中是的。 flatten正是如此:“将对的任意S表达式结构展平为列表。”
Examples:
> (flatten '((a) b (c (d) . e) ()))
'(a b c d e)
> (flatten 'a)
'(a)
然而,考虑一下如何自己写flatten
是一个很好的练习。
Chris Jester-Young的评论链接到一种优雅的方式。如果她将其作为答案发布,而不是作为评论,我建议将她的答案标记为已接受,而不是我的。 :)
答案 1 :(得分: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)。 / p>
(警告:我不是Scheme大师;上面的代码可能包含错误。)
答案 2 :(得分:1)
你的案件应该包括空列表,原子,(汽车)是一个原子,(汽车)是一个列表。
这很有效,虽然我打破了一个列表附加功能,因为我不记得内置功能。适用于球拍高级学生。
(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))))))
答案 3 :(得分:1)
现在,如果您想要更快的实施,则根本不需要append
。
这个想法是传递你要附加的参数。我叫这个尾巴。 如果你有一个空的s-exp,你只需返回尾部,因为没有任何内容可以添加。
我有代码flat
和flat2
,其中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)
。
你需要为它们提供空列表。
答案 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)
>