我在编写一个程序的过程中遇到了一些困难,这个程序会使列表变平一次,即
(flatten-once '((b) (c f) ((d)(e))))
会生成'(b c f (d) (e)))
。我查看了几个关于标准flatten过程如何工作的来源,但它实现了我需要使用的intermediate student with lambda
语言形式中未包含的函数。据我所知,foldr
会有所帮助,并设法得到这个
(define (flatten-once lst)
(cond
[(empty? lst) lst]
[else
((foldr cons (first (rest lst)) (first lst)))]))
返回'(b c f)
,所以我想它会使列表的一部分变平。我尝试通过递归继续定义,但这只是错误,所以我想我错过了一些东西。
答案 0 :(得分:7)
建议的代码过于复杂,抵制在任何地方使用折叠的诱惑,它们不是所有东西的答案 - 我这样说是因为我已经看到了你的其他问题而且经常会有一个不必要的调用{{1 }或foldr
。一个简单的foldl
就可以解决问题:
append
按预期工作:
(define (flatten-once lst)
(apply append lst))
如果输入列表包含非列表的元素,则需要完成更多工作。要非常小心,我们可以这样做:
(flatten-once '((b) (c f) ((d)(e))))
=> '(b c f (d) (e))
现在它适用于此类输入,注意到元素(define (flatten-once lst)
(apply append
(map (lambda (e) (if (cons? e) e (list e)))
lst)))
已添加到列表中。另一种方法是从列表中删除,如果更有意义,则在上面的代码中用a
替换(list e)
。
'()
最后,根据@Alex的回答,第二个变体也可以使用(flatten-once '(a (b) (c f) ((d)(e))))
=> '(a b c f (d) (e))
编写:
foldr
答案 1 :(得分:2)
正如ÓscarLópez已经说过的那样,使用append
。
如果您想使用foldr
的解决方案:
(define (flatten-once lst)
(foldr append '() lst))
它应该按预期工作。
答案 2 :(得分:1)
奥斯卡的版本不太优雅,但没有append
(在我的测试中速度提高一倍):
(define (flatten-once lst)
(reverse
(let loop ((lst lst) (first #t) (res null))
(if (null? lst)
res
(let ((e (car lst)))
(loop (cdr lst)
first
(if (and first (cons? e))
(loop e #f res)
(cons e res))))))))
在intermediate student with lambda language
中注意,这需要表达为:
(define (flatten-once-helper lst first res)
(if (null? lst)
res
(let ((e (car lst)))
(flatten-once-helper
(cdr lst)
first
(if (and first (cons? e))
(flatten-once-helper e #f res)
(cons e res))))))
(define (flatten-once lst)
(reverse (flatten-once-helper lst #t null)))